diff --git a/INSTALL b/INSTALL index c493b7b3cc2773b38455b642cfdab4fa1116a73b..56b077d6a0b8773b014bd4381cc09abb17fff351 100644 --- a/INSTALL +++ b/INSTALL @@ -1,7 +1,6 @@ Installation Instructions ************************* - Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. diff --git a/Makefile.am b/Makefile.am index 58dc0abfaf83e52596353cac5b6fdcd734592dcb..698adb4bd0cb5c1452a2f9c0bb1cb5d778b2b087 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,2 +1,5 @@ -SUBDIRS = utilspp stund src ringtones +SUBDIRS = exosip2 utilspp stund src ringtones m4 EXTRA_DIST = tools/*.sh + +ACLOCAL_FLAGS=-I$(top_srcdir)/m4 + diff --git a/config.guess b/config.guess index 45bee139873061344c27d4e7ca547ca8930374e7..2fc3acce2ea194699db402e89d32d5b10b0369a3 100755 --- a/config.guess +++ b/config.guess @@ -1,9 +1,9 @@ #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. -timestamp='2005-04-22' +timestamp='2003-06-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -53,7 +53,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO @@ -136,6 +136,13 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown +## for Red Hat Linux +if test -f /etc/redhat-release ; then + VENDOR=redhat ; +else + VENDOR= ; +fi + # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in @@ -197,21 +204,15 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; - amd64:OpenBSD:*:*) - echo x86_64-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; - cats:OpenBSD:*:*) - echo arm-unknown-openbsd${UNAME_RELEASE} + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; - luna88k:OpenBSD:*:*) - echo m88k-unknown-openbsd${UNAME_RELEASE} - exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; @@ -227,33 +228,25 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; sgi:OpenBSD:*:*) - echo mips64-unknown-openbsd${UNAME_RELEASE} + echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; - *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} - exit 0 ;; - macppc:MirBSD:*:*) - echo powerppc-unknown-mirbsd${UNAME_RELEASE} - exit 0 ;; - *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} - exit 0 ;; alpha:OSF1:*:*) - case $UNAME_RELEASE in - *4.0) + if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac + fi # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU @@ -291,12 +284,14 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac - # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha*:OpenVMS:*:*) + echo alpha-hp-vms exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? @@ -319,12 +314,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; - *:z/VM:*:*) - echo s390-ibm-zvmoe - exit 0 ;; - *:OS400:*:*) - echo powerpc-ibm-os400 - exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; @@ -345,7 +334,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; @@ -417,9 +406,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; - m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; @@ -755,7 +741,7 @@ EOF echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` @@ -763,11 +749,6 @@ EOF FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; @@ -777,8 +758,19 @@ EOF *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; - *:FreeBSD:*:*) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + *:FreeBSD:*:*|*:GNU/FreeBSD:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin @@ -804,9 +796,6 @@ EOF i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; - amd64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; @@ -814,13 +803,8 @@ EOF echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) - # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu - exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; @@ -830,17 +814,8 @@ EOF cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; - crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu - exit 0 ;; - frv:Linux:*:*) - echo frv-unknown-linux-gnu - exit 0 ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit 0 ;; - m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-${VENDOR:-unknown}-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu @@ -884,10 +859,10 @@ EOF test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu + echo powerpc-${VENDOR:-unknown}-linux-gnu exit 0 ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu + echo powerpc64-${VENDOR:-unknown}-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in @@ -915,7 +890,7 @@ EOF echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux + echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu @@ -927,7 +902,7 @@ EOF echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu + echo x86_64-${VENDOR:-unknown}-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so @@ -977,12 +952,9 @@ EOF LIBC=gnuaout #endif #endif - #ifdef __dietlibc__ - LIBC=dietlibc - #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` - test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR:-pc}-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) @@ -1010,9 +982,6 @@ EOF i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; - i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable - exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; @@ -1082,9 +1051,9 @@ EOF M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; - M68*:*:R3V[5678]*:*) + M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` @@ -1140,10 +1109,6 @@ EOF # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; - i*86:VOS:*:*) - # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos - exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos @@ -1186,10 +1151,9 @@ EOF echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - case $UNAME_PROCESSOR in + case `uname -p` in *86) UNAME_PROCESSOR=i686 ;; - unknown) UNAME_PROCESSOR=powerpc ;; + powerpc) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; @@ -1204,10 +1168,7 @@ EOF *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; - NSE-?:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit 0 ;; - NSR-?:NONSTOP_KERNEL:*:*) + NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) @@ -1251,19 +1212,6 @@ EOF SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; - *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit 0 ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms && exit 0 ;; - I*) echo ia64-dec-vms && exit 0 ;; - V*) echo vax-dec-vms && exit 0 ;; - esac ;; - *:XENIX:*:SysV) - echo i386-pc-xenix - exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 @@ -1423,9 +1371,7 @@ This script, last modified $timestamp, has failed to recognize the operating system you are using. It is advised that you download the most up to date version of the config scripts from - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess -and - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub + ftp://ftp.gnu.org/pub/gnu/config/ If the version you run ($0) is already up to date, please send the following data and any information you think might be diff --git a/config.h.in b/config.h.in index 0962968911700cf59b15b3ff3e64c7ef917107e4..8af0e482645c6582485745eb15002a3f8dba89a4 100644 --- a/config.h.in +++ b/config.h.in @@ -1,17 +1,29 @@ /* config.h.in. Generated from configure.ac by autoheader. */ +/* Define to 1 if you have the <assert.h> header file. */ +#undef HAVE_ASSERT_H + +/* Define to 1 if you have the <ctype.h> header file. */ +#undef HAVE_CTYPE_H + /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H /* Define if dns-sd is available */ #undef HAVE_DNSSD -/* Define to 1 if you have the <eXosip2/eXosip.h> header file. */ -#undef HAVE_EXOSIP2_EXOSIP_H +/* Define to 1 if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `osipparser2' library (-losipparser2). */ +#undef HAVE_LIBOSIPPARSER2 + +/* Define to 1 if you have the <malloc.h> header file. */ +#undef HAVE_MALLOC_H + /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H @@ -21,9 +33,24 @@ /* Define to 1 if you have the <portaudio.h> header file. */ #undef HAVE_PORTAUDIO_H +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Define to 1 if you have the <semaphore.h> header file. */ +#undef HAVE_SEMAPHORE_H + +/* Define to 1 if you have the <signal.h> header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if you have the <stdarg.h> header file. */ +#undef HAVE_STDARG_H + /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the <stdio.h> header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H @@ -33,15 +60,30 @@ /* Define to 1 if you have the <string.h> header file. */ #undef HAVE_STRING_H +/* Define to 1 if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the <sys/sem.h> header file. */ +#undef HAVE_SYS_SEM_H + +/* Define to 1 if you have the <sys/signal.h> header file. */ +#undef HAVE_SYS_SIGNAL_H + /* Define to 1 if you have the <sys/stat.h> header file. */ #undef HAVE_SYS_STAT_H +/* Define to 1 if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + /* Define to 1 if you have the <sys/types.h> header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the <varargs.h> header file. */ +#undef HAVE_VARARGS_H + /* Name of package */ #undef PACKAGE @@ -60,6 +102,10 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION +/* Define to the necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS diff --git a/config.sub b/config.sub index 87a1ee49e67b1ab68f3ba88dc81eb3bc4449d96d..6b2ff9f6a7a89034532915972c4a1034fddf5bce 100755 --- a/config.sub +++ b/config.sub @@ -1,9 +1,9 @@ #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. -timestamp='2005-04-22' +timestamp='2003-06-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -70,7 +70,7 @@ Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO @@ -118,8 +118,7 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ - kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; @@ -145,7 +144,7 @@ case $os in -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray) + -apple | -axis) os= basic_machine=$1 ;; @@ -229,16 +228,14 @@ case $basic_machine in | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ - | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | ip2k \ + | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ @@ -250,7 +247,6 @@ case $basic_machine in | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ @@ -261,15 +257,15 @@ case $basic_machine in | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ + | s390 | s390x \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ - | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; @@ -300,19 +296,19 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ - | bfin-* | bs2000-* \ + | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ - | clipper-* | craynv-* | cydra-* \ + | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | m32r-* | m32rle-* \ + | ip2k-* \ + | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* \ + | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ @@ -324,30 +320,28 @@ case $basic_machine in | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ - | mmix-* \ | msp430-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ + | s390-* | s390x-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ - | sparclite-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ - | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ - | xstormy16-* | xtensa-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ | ymp-* \ | z8k-*) ;; @@ -367,9 +361,6 @@ case $basic_machine in basic_machine=a29k-amd os=-udi ;; - abacus) - basic_machine=abacus-unknown - ;; adobe68k) basic_machine=m68010-adobe os=-scout @@ -387,9 +378,6 @@ case $basic_machine in amd64) basic_machine=x86_64-pc ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; amdahl) basic_machine=580-amdahl os=-sysv @@ -449,27 +437,12 @@ case $basic_machine in basic_machine=j90-cray os=-unicos ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16c) - basic_machine=cr16c-unknown - os=-elf - ;; crds | unos) basic_machine=m68k-crds ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; da30 | da30-*) basic_machine=m68k-da30 ;; @@ -492,10 +465,6 @@ case $basic_machine in basic_machine=m88k-motorola os=-sysv3 ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx @@ -674,6 +643,10 @@ case $basic_machine in mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; monitor) basic_machine=m68k-rom68k os=-coff @@ -754,6 +727,10 @@ case $basic_machine in np1) basic_machine=np1-gould ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; nsr-tandem) basic_machine=nsr-tandem ;; @@ -765,10 +742,6 @@ case $basic_machine in basic_machine=or32-unknown os=-coff ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose @@ -860,12 +833,6 @@ case $basic_machine in rtpc | rtpc-*) basic_machine=romp-ibm ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; sa29200) basic_machine=a29k-amd os=-udi @@ -989,10 +956,6 @@ case $basic_machine in tower | tower-32) basic_machine=m68k-ncr ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; udi29k) basic_machine=a29k-amd os=-udi @@ -1036,10 +999,6 @@ case $basic_machine in basic_machine=hppa1.1-winbond os=-proelf ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; xps | xps100) basic_machine=xps100-honeywell ;; @@ -1070,9 +1029,6 @@ case $basic_machine in romp) basic_machine=romp-ibm ;; - mmix) - basic_machine=mmix-knuth - ;; rs6000) basic_machine=rs6000-ibm ;; @@ -1168,20 +1124,19 @@ case $os in | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) + | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1205,9 +1160,6 @@ case $os in -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; @@ -1220,9 +1172,6 @@ case $os in -opened*) os=-openedition ;; - -os400*) - os=-os400 - ;; -wince*) os=-wince ;; @@ -1244,9 +1193,6 @@ case $os in -atheos*) os=-atheos ;; - -syllable*) - os=-syllable - ;; -386bsd) os=-bsd ;; @@ -1269,9 +1215,6 @@ case $os in -sinix*) os=-sysv4 ;; - -tpf*) - os=-tpf - ;; -triton*) os=-sysv3 ;; @@ -1308,9 +1251,6 @@ case $os in -kaos*) os=-kaos ;; - -zvmoe) - os=-zvmoe - ;; -none) ;; *) @@ -1342,9 +1282,9 @@ case $basic_machine in arm*-semi) os=-aout ;; - c4x-* | tic4x-*) - os=-coff - ;; + c4x-* | tic4x-*) + os=-coff + ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 @@ -1391,9 +1331,6 @@ case $basic_machine in *-ibm) os=-aix ;; - *-knuth) - os=-mmixware - ;; *-wec) os=-proelf ;; @@ -1526,15 +1463,9 @@ case $basic_machine in -mvs* | -opened*) vendor=ibm ;; - -os400*) - vendor=ibm - ;; -ptx*) vendor=sequent ;; - -tpf*) - vendor=ibm - ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; diff --git a/configure.ac b/configure.ac index 3ec02f6e8072688f1ac57b7afe173deaf1f548bf..4a09a029a4fd9458bb5c725fc9ba1e9201dda604 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(acinclude.m4) +AC_INIT(aclocal.m4) AM_CONFIG_HEADER(config.h) @@ -31,9 +31,8 @@ dnl KDE_USE_QT(3.3) AC_CANONICAL_SYSTEM AC_ARG_PROGRAM AM_INIT_AUTOMAKE(sflphoned, $VERSION) -AM_DISABLE_LIBRARIES AC_PROG_LIBTOOL -AC_CHECK_COMPILERS +dnl AC_CHECK_COMPILERS CXXFLAGS="$CXXFLAGS $USE_EXCEPTIONS" @@ -54,7 +53,6 @@ dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS( \ ostream \ -eXosip2/eXosip.h \ portaudio.h \ ) @@ -73,22 +71,17 @@ PKG_CHECK_MODULES(libccrtp1, libccrtp1 >= ${LIBCCRT_MIN_VERSION}) SFLPHONE_CXXFLAGS="$SFLPHONE_CXXFLAGS $libccrtp1_CFLAGS" SFLPHONE_LIBS="$SFLPHONE_LIBS $libccrtp1_LIBS" -dnl 2.2.0 is buggy, header corruption -LIBOSIP2_MIN_VERSION=2.2.1 -PKG_CHECK_MODULES(libosip2, libosip2 >= ${LIBOSIP2_MIN_VERSION}) -SFLPHONE_CXXFLAGS="$SFLPHONE_CXXFLAGS $libosip2_CFLAGS" -SFLPHONE_LIBS="$SFLPHONE_LIBS $libosip2_LIBS" +dnl check for osip2 +LP_CHECK_OSIP2 -if test $ac_cv_header_eXosip2_eXosip_h = no; then - AC_MSG_ERROR([*** missing eXosip2/eXosip.h. You need a working eXosip2 installation. See http://www.antisip.com/download/]) -fi - -AC_CHECK_LIB([eXosip2], [eXosip_init],[libexosip2_LIBS="-leXosip2 "],[ - AC_MSG_ERROR([*** missing eXosip2 library. You need a working eXosip2 installation. See http://www.antisip.com/download/])]) +dnl setup flags for embedded exosip library +LP_SETUP_EXOSIP -SFLPHONE_LIBS="$SFLPHONE_LIBS $libexosip2_LIBS" +SFLPHONE_CXXFLAGS="$SFLPHONE_CXXFLAGS $OSIP_CFLAGS" +SFLPHONE_LIBS="$SFLPHONE_LIBS $OSIP_LIBS" +SFLPHONE_CXXFLAGS="$SFLPHONE_CXXFLAGS $EXOSIP_CFLAGS" +SFLPHONE_LIBS="$SFLPHONE_LIBS $EXOSIP_LIBS" -dnl AC_SUBST(LIBQT) if test $ac_cv_header_portaudio_h = no; then AC_MSG_ERROR([*** missing portaudio.h. You need a working PortAudio installation. See http://www.portaudio.com]) @@ -142,13 +135,13 @@ fi AC_SUBST(LIB_DNSSD) AM_CONDITIONAL(USE_ZEROCONF, test "$have_libdns_sd" = "yes") -AC_CONFIG_SUBDIRS(src/gui/qt) - dnl AC_CONFIG_FILES( AC_OUTPUT( sflphone.spec \ sflphoned-fedora.spec \ Makefile \ +m4/Makefile \ +exosip2/Makefile \ src/Makefile \ src/sflphone \ src/audio/Makefile \ diff --git a/deps/Makefile.am b/deps/Makefile.am index b9b47071d6bc98a15a7bce1b16288d110b1e7e46..e6e60a95220eade09829175617a6ff0c5eeb6f9d 100644 --- a/deps/Makefile.am +++ b/deps/Makefile.am @@ -10,5 +10,5 @@ if COMPILE_PORTAUDIO PORTAUDIO = portaudio endif -SUBDIRS = $(OSIP) $(EXOSIP) $(PORTAUDIO) +SUBDIRS = $(PORTAUDIO) diff --git a/exosip2/Makefile.am b/exosip2/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..a3ef5a35dc7ce2dbed2370ed16f7053baf5b5e87 --- /dev/null +++ b/exosip2/Makefile.am @@ -0,0 +1,33 @@ + + +lib_LTLIBRARIES = libeXosip2.la + +# +# Other flags to add someday: +# -Wcast-qual +# -Wwrite-strings +# -Wstrict-prototypes +# -Werror +# +AM_CFLAGS = @EXOSIP_CFLAGS@ @CFLAGS@ + +libeXosip2_la_SOURCES = \ +eXosip.c eXconf.c \ +eXregister_api.c eXsubscription_api.c \ +eXcall_api.c eXoptions_api.c \ +eXrefer_api.c eXmessage_api.c \ +eXinsubscription_api.c eXpublish_api.c \ +eXtransport.c \ +inet_ntop.c inet_ntop.h \ +jrequest.c jresponse.c \ +jcallback.c jdialog.c udp.c \ +jcall.c jreg.c eXutils.c \ +jnotify.c jsubscribe.c jevents.c \ +misc.c eXosip2.h \ +jpipe.c jpipe.h jauth.c \ +sdp_offans.c jpublish.c + +libeXosip2_la_LDFLAGS = -L$(prefix)/lib -version-info $(LIBEXOSIP_SO_VERSION) +libeXosip2_la_LIBADD = -losip2 @EXOSIP_LIBS@ + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/include -I$(includedir) diff --git a/exosip2/eXcall_api.c b/exosip2/eXcall_api.c new file mode 100644 index 0000000000000000000000000000000000000000..76dc9a8fc73c438763817dba3f47a47d2725f6ba --- /dev/null +++ b/exosip2/eXcall_api.c @@ -0,0 +1,1563 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +static int eXosip_create_transaction (eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_message_t * request); +static int eXosip_create_cancel_transaction (eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_message_t * request); +static int _eXosip_call_transaction_find (int tid, eXosip_call_t ** jc, + eXosip_dialog_t ** jd, + osip_transaction_t ** tr); + +static int +eXosip_create_transaction (eXosip_call_t * jc, + eXosip_dialog_t * jd, osip_message_t * request) +{ + osip_event_t *sipevent; + osip_transaction_t *tr; + int i; + + i = osip_transaction_init (&tr, NICT, eXosip.j_osip, request); + if (i != 0) + { + /* TODO: release the j_call.. */ + + osip_message_free (request); + return -1; + } + + if (jd != NULL) + osip_list_add (jd->d_out_trs, tr, 0); + + sipevent = osip_new_outgoing_sipmessage (request); + sipevent->transactionid = tr->transactionid; + + osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (jc, jd, NULL, NULL)); + osip_transaction_add_event (tr, sipevent); + __eXosip_wakeup (); + return 0; +} + +static int +eXosip_create_cancel_transaction (eXosip_call_t * jc, + eXosip_dialog_t * jd, osip_message_t * request) +{ + osip_event_t *sipevent; + osip_transaction_t *tr; + int i; + + i = osip_transaction_init (&tr, NICT, eXosip.j_osip, request); + if (i != 0) + { + /* TODO: release the j_call.. */ + + osip_message_free (request); + return -2; + } + + osip_list_add (eXosip.j_transactions, tr, 0); + + sipevent = osip_new_outgoing_sipmessage (request); + sipevent->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, sipevent); + __eXosip_wakeup (); + return 0; +} + +static int +_eXosip_call_transaction_find (int tid, eXosip_call_t ** jc, + eXosip_dialog_t ** jd, osip_transaction_t ** tr) +{ + for (*jc = eXosip.j_calls; *jc != NULL; *jc = (*jc)->next) + { + if ((*jc)->c_inc_tr != NULL && (*jc)->c_inc_tr->transactionid == tid) + { + *tr = (*jc)->c_inc_tr; + *jd = (*jc)->c_dialogs; + return 0; + } + if ((*jc)->c_out_tr != NULL && (*jc)->c_out_tr->transactionid == tid) + { + *tr = (*jc)->c_out_tr; + *jd = (*jc)->c_dialogs; + return 0; + } + for (*jd = (*jc)->c_dialogs; *jd != NULL; *jd = (*jd)->next) + { + osip_transaction_t *transaction; + int pos = 0; + + while (!osip_list_eol ((*jd)->d_inc_trs, pos)) + { + transaction = + (osip_transaction_t *) osip_list_get ((*jd)->d_inc_trs, pos); + if (transaction != NULL && transaction->transactionid == tid) + { + *tr = transaction; + return 0; + } + pos++; + } + + pos = 0; + while (!osip_list_eol ((*jd)->d_out_trs, pos)) + { + transaction = + (osip_transaction_t *) osip_list_get ((*jd)->d_out_trs, pos); + if (transaction != NULL && transaction->transactionid == tid) + { + *tr = transaction; + return 0; + } + pos++; + } + } + } + *jd = NULL; + *jc = NULL; + return -1; +} + +int +eXosip_call_set_reference (int id, void *reference) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + + if (id > 0) + { + eXosip_call_dialog_find (id, &jc, &jd); + if (jc == NULL) + { + eXosip_call_find (id, &jc); + } + } + if (jc == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + jc->external_reference = reference; + return 0; +} + +/* this method can't be called unless the previous + INVITE transaction is over. */ +int +eXosip_call_build_initial_invite (osip_message_t ** invite, + const char *to, + const char *from, + const char *route, const char *subject) +{ + int i; + osip_uri_param_t *uri_param = NULL; + osip_to_t *_to=NULL; + + *invite = NULL; + + if (to != NULL && *to == '\0') + return -1; + if (route != NULL && *route == '\0') + route = NULL; + if (subject != NULL && *subject == '\0') + subject = NULL; + + i = osip_to_init(&_to); + if (i!=0) + return -1; + + i = osip_to_parse(_to, to); + if (i!=0) + { + osip_to_free(_to); + return -1; + } + + osip_uri_uparam_get_byname(_to->url, "transport", &uri_param); + if (uri_param != NULL && uri_param->gvalue != NULL) + { + i = generating_request_out_of_dialog (invite, "INVITE", to, uri_param->gvalue, from, route); + } + else + { + if (eXosip.net_interfaces[0].net_socket>0) + i = generating_request_out_of_dialog (invite, "INVITE", to, "UDP", from, route); + else if (eXosip.net_interfaces[1].net_socket>0) + i = generating_request_out_of_dialog (invite, "INVITE", to, "TCP", from, route); + else + i = generating_request_out_of_dialog (invite, "INVITE", to, "UDP", from, route); + } + osip_to_free(_to); + if (i != 0) + return -1; + + if (subject != NULL) + osip_message_set_subject (*invite, subject); + + /* after this delay, we should send a CANCEL */ + osip_message_set_expires (*invite, "120"); + return 0; +} + +int +eXosip_call_send_initial_invite (osip_message_t * invite) +{ + eXosip_call_t *jc; + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + eXosip_call_init (&jc); + + i = osip_transaction_init (&transaction, ICT, eXosip.j_osip, invite); + if (i != 0) + { + eXosip_call_free (jc); + osip_message_free (invite); + return -1; + } + + jc->c_out_tr = transaction; + + sipevent = osip_new_outgoing_sipmessage (invite); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, NULL, NULL, NULL)); + osip_transaction_add_event (transaction, sipevent); + + jc->external_reference = NULL; + ADD_ELEMENT (eXosip.j_calls, jc); + + eXosip_update (); /* fixed? */ + __eXosip_wakeup (); + return jc->c_id; +} + +int +eXosip_call_build_ack (int did, osip_message_t ** _ack) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + osip_transaction_t *tr = NULL; + + osip_message_t *ack; + char *transport; + int i; + + *_ack = NULL; + + if (did > 0) + { + eXosip_call_dialog_find (did, &jc, &jd); + } + if (jc == NULL || jd == NULL || jd->d_dialog == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + + tr = eXosip_find_last_invite (jc, jd); + + if (tr == NULL || tr->orig_request == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No transaction for call?\n")); + return -1; + } + + if (0 != osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: ACK are only sent for invite transactions\n")); + return -1; + } + + transport = NULL; + transport = _eXosip_transport_protocol(tr->orig_request); + if (transport==NULL) + i = _eXosip_build_request_within_dialog (&ack, "ACK", jd->d_dialog, "UDP"); + else + i = _eXosip_build_request_within_dialog (&ack, "ACK", jd->d_dialog, transport); + + if (i != 0) + { + return -1; + } + + /* Fix CSeq Number when request has been exchanged during INVITE transactions */ + if (tr->orig_request->cseq!=NULL && tr->orig_request->cseq->number!=NULL) + { + if (ack!=NULL && ack->cseq!=NULL && ack->cseq->number!=NULL) + { + osip_free(ack->cseq->number); + ack->cseq->number = osip_strdup(tr->orig_request->cseq->number); + } + } + + /* copy all credentials from INVITE! */ + { + int pos = 0; + int i; + osip_proxy_authorization_t *pa = NULL; + + i = osip_message_get_proxy_authorization (tr->orig_request, pos, &pa); + while (i == 0 && pa != NULL) + { + osip_proxy_authorization_t *pa2; + + i = osip_proxy_authorization_clone (pa, &pa2); + if (i != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Error in credential from INVITE\n")); + break; + } + osip_list_add (ack->proxy_authorizations, pa2, -1); + pa = NULL; + pos++; + i = osip_message_get_proxy_authorization (tr->orig_request, pos, &pa); + } + } + + *_ack = ack; + return 0; +} + +int +eXosip_call_send_ack (int did, osip_message_t * ack) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + + osip_route_t *route; + char *host; + int port; + + if (did > 0) + { + eXosip_call_dialog_find (did, &jc, &jd); + } + + if (jc == NULL || jd == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + if (ack != NULL) + osip_message_free (ack); + return -1; + } + + if (ack == NULL) + { + int i; + + i = eXosip_call_build_ack (did, &ack); + if (i != 0) + { + return -1; + } + } + + osip_message_get_route (ack, 0, &route); + if (route != NULL) + { + osip_uri_param_t *lr_param=NULL; + osip_uri_uparam_get_byname (route->url, "lr", &lr_param); + if (lr_param==NULL) + route=NULL; + } + + if (route != NULL) + { + port = 5060; + if (route->url->port != NULL) + port = osip_atoi (route->url->port); + host = route->url->host; + } else + { + port = 5060; + if (ack->req_uri->port != NULL) + port = osip_atoi (ack->req_uri->port); + host = ack->req_uri->host; + } + + cb_snd_message (NULL, ack, host, port, -1); + + if (jd->d_ack != NULL) + osip_message_free (jd->d_ack); + jd->d_ack = ack; + return 0; +} + +int +eXosip_call_build_request (int jid, const char *method, osip_message_t ** request) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + + osip_transaction_t *transaction; + char *transport; + int i; + + *request = NULL; + if (method == NULL || method[0] == '\0') + return -1; + + if (jid > 0) + { + eXosip_call_dialog_find (jid, &jc, &jd); + } + if (jd == NULL || jd->d_dialog == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + + transaction = NULL; + if (0 == osip_strcasecmp (method, "INVITE")) + { + transaction = eXosip_find_last_invite (jc, jd); + } else /* OPTIONS, UPDATE, INFO, REFER, ?... */ + { + transaction = eXosip_find_last_transaction (jc, jd, method); + } + + if (transaction != NULL) + { + if (0 != osip_strcasecmp (method, "INVITE")) + { + if (transaction->state != NICT_TERMINATED && + transaction->state != NIST_TERMINATED && + transaction->state != NICT_COMPLETED && + transaction->state != NIST_COMPLETED) + return -1; + } else + { + if (transaction->state != ICT_TERMINATED && + transaction->state != IST_TERMINATED && + transaction->state != IST_CONFIRMED && + transaction->state != ICT_COMPLETED) + return -1; + } + } + + transport = NULL; + transaction = eXosip_find_last_invite (jc, jd); + if (transaction!=NULL && transaction->orig_request!=NULL) + transport = _eXosip_transport_protocol(transaction->orig_request); + + transaction = NULL; + + if (transport==NULL) + i = _eXosip_build_request_within_dialog (request, method, jd->d_dialog, "UDP"); + else + i = _eXosip_build_request_within_dialog (request, method, jd->d_dialog, transport); + if (i != 0) + return -2; + + if (jc->response_auth!=NULL) + eXosip_add_authentication_information (*request, jc->response_auth); + + return 0; +} + +int +eXosip_call_send_request (int jid, osip_message_t * request) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + + osip_transaction_t *transaction; + osip_event_t *sipevent; + + int i; + + if (request == NULL) + return -1; + + if (request->sip_method == NULL) + { + osip_message_free (request); + return -1; + } + + if (jid > 0) + { + eXosip_call_dialog_find (jid, &jc, &jd); + } + if (jd == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + osip_message_free (request); + return -1; + } + + transaction = NULL; + if (0 == osip_strcasecmp (request->sip_method, "INVITE")) + { + transaction = eXosip_find_last_invite (jc, jd); + } else /* OPTIONS, UPDATE, INFO, REFER, ?... */ + { + transaction = eXosip_find_last_transaction (jc, jd, request->sip_method); + } + + if (transaction != NULL) + { + if (0 != osip_strcasecmp (request->sip_method, "INVITE")) + { + if (transaction->state != NICT_TERMINATED && + transaction->state != NIST_TERMINATED && + transaction->state != NICT_COMPLETED && + transaction->state != NIST_COMPLETED) + { + osip_message_free (request); + return -1; + } + } else + { + if (transaction->state != ICT_TERMINATED && + transaction->state != IST_TERMINATED && + transaction->state != IST_CONFIRMED && + transaction->state != ICT_COMPLETED) + { + osip_message_free (request); + return -1; + } + } + } + + transaction = NULL; + if (0 != osip_strcasecmp (request->sip_method, "INVITE")) + { + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, request); + } else + { + i = osip_transaction_init (&transaction, ICT, eXosip.j_osip, request); + } + + if (i != 0) + { + osip_message_free (request); + return -2; + } + + osip_list_add (jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage (request); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + osip_transaction_add_event (transaction, sipevent); + __eXosip_wakeup (); + return 0; +} + +int +eXosip_call_build_refer (int did, const char *refer_to, osip_message_t ** request) +{ + int i; + + *request = NULL; + i = eXosip_call_build_request (did, "REFER", request); + if (i != 0) + return -1; + + if (refer_to == NULL || refer_to[0] == '\0') + return 0; + + osip_message_set_header (*request, "Refer-to", refer_to); + return 0; +} + +int +eXosip_call_build_options (int did, osip_message_t ** request) +{ + int i; + + *request = NULL; + i = eXosip_call_build_request (did, "OPTIONS", request); + if (i != 0) + return -1; + + return 0; +} + +int +eXosip_call_build_info (int did, osip_message_t ** request) +{ + int i; + + *request = NULL; + i = eXosip_call_build_request (did, "INFO", request); + if (i != 0) + return -1; + + return 0; +} + +int +eXosip_call_build_update (int did, osip_message_t ** request) +{ + int i; + + *request = NULL; + i = eXosip_call_build_request (did, "UPDATE", request); + if (i != 0) + return -1; + + return 0; +} + +int +eXosip_call_build_notify (int did, int subscription_status, + osip_message_t ** request) +{ + char subscription_state[50]; + char *tmp; + int i; + + *request = NULL; + i = eXosip_call_build_request (did, "NOTIFY", request); + if (i != 0) + return -1; + + if (subscription_status == EXOSIP_SUBCRSTATE_PENDING) + osip_strncpy (subscription_state, "pending;expires=", 16); + else if (subscription_status == EXOSIP_SUBCRSTATE_ACTIVE) + osip_strncpy (subscription_state, "active;expires=", 15); + else if (subscription_status == EXOSIP_SUBCRSTATE_TERMINATED) + { + int reason = NORESOURCE; + + if (reason == DEACTIVATED) + osip_strncpy (subscription_state, "terminated;reason=deactivated", 29); + else if (reason == PROBATION) + osip_strncpy (subscription_state, "terminated;reason=probation", 27); + else if (reason == REJECTED) + osip_strncpy (subscription_state, "terminated;reason=rejected", 26); + else if (reason == TIMEOUT) + osip_strncpy (subscription_state, "terminated;reason=timeout", 25); + else if (reason == GIVEUP) + osip_strncpy (subscription_state, "terminated;reason=giveup", 24); + else if (reason == NORESOURCE) + osip_strncpy (subscription_state, "terminated;reason=noresource", 29); + } + tmp = subscription_state + strlen (subscription_state); + if (subscription_status != EXOSIP_SUBCRSTATE_TERMINATED) + sprintf (tmp, "%i", 180); + osip_message_set_header (*request, "Subscription-State", subscription_state); + + return 0; +} + +int +eXosip_call_build_answer (int tid, int status, osip_message_t ** answer) +{ + int i = -1; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + osip_transaction_t *tr = NULL; + + *answer = NULL; + + if (tid > 0) + { + _eXosip_call_transaction_find (tid, &jc, &jd, &tr); + } + if (tr == NULL || jd == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + + if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) + { + if (status > 100 && status < 200) + { + i = _eXosip_answer_invite_1xx (jc, jd, status, answer); + } else if (status > 199 && status < 300) + { + i = _eXosip_answer_invite_2xx (jc, jd, status, answer); + } else if (status > 300 && status < 699) + { + i = _eXosip_answer_invite_3456xx (jc, jd, status, answer); + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (101<status<699)\n")); + return -1; + } + } else + { + if (jd != NULL) + { + i = + _eXosip_build_response_default (answer, jd->d_dialog, status, + tr->orig_request); + } else + { + i = + _eXosip_build_response_default (answer, NULL, status, + tr->orig_request); + } + if (status>100 && status < 300 ) + i = complete_answer_that_establish_a_dialog (*answer, tr->orig_request); + } + + if (i != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: Could not create response for %s\n", + tr->orig_request->sip_method)); + return -1; + } + return 0; +} + +int +eXosip_call_send_answer (int tid, int status, osip_message_t * answer) +{ + int i = -1; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + osip_transaction_t *tr = NULL; + osip_event_t *evt_answer; + + if (tid > 0) + { + _eXosip_call_transaction_find (tid, &jc, &jd, &tr); + } + if (jd == NULL || tr == NULL || tr->orig_request == NULL + || tr->orig_request->sip_method == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here or no transaction for call\n")); + osip_message_free (answer); + return -1; + } + + if (answer == NULL) + { + if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) + { + if (status >= 100 && status <= 199) + { + } else if (status >= 300 && status <= 699) + { + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Wrong parameter?\n")); + osip_message_free (answer); + return -1; + } + } + } + + /* is the transaction already answered? */ + if (tr->state == IST_COMPLETED + || tr->state == IST_CONFIRMED + || tr->state == IST_TERMINATED + || tr->state == NIST_COMPLETED || tr->state == NIST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + osip_message_free (answer); + return -1; + } + + if (answer == NULL) + { + if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) + { + if (status < 200) + i = _eXosip_default_answer_invite_1xx (jc, jd, status); + else + i = _eXosip_default_answer_invite_3456xx (jc, jd, status); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot send response!\n")); + return -1; + } + } else + { + /* TODO */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: a response must be given!\n")); + return -1; + } + return 0; + } else + { + i = 0; + } + + if (0 == osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) + { + if (MSG_IS_STATUS_1XX (answer)) + { + if (jd == NULL) + { + i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, answer); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + i = 0; + } else + { + ADD_ELEMENT (jc->c_dialogs, jd); + } + } + } else if (MSG_IS_STATUS_2XX (answer)) + { + if (jd == NULL) + { + i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, answer); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + osip_message_free (answer); + return -1; + } + ADD_ELEMENT (jc->c_dialogs, jd); + } else + i = 0; + + eXosip_dialog_set_200ok (jd, answer); + osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED); + } else if (answer->status_code >= 300 && answer->status_code <= 699) + { + i = 0; + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (101<status<699)\n")); + osip_message_free (answer); + return -1; + } + if (i != 0) + { + osip_message_free (answer); + return -1; + } + } + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + eXosip_update (); + __eXosip_wakeup (); + return 0; +} + +int +eXosip_call_terminate (int cid, int did) +{ + int i; + osip_transaction_t *tr; + osip_message_t *request = NULL; + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + char *transport=NULL; + + if (did > 0) + { + eXosip_call_dialog_find (did, &jc, &jd); + if (jd == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + } else + { + eXosip_call_find (cid, &jc); + } + + if (jc == NULL) + { + return -1; + } + + tr = eXosip_find_last_out_invite (jc, jd); + if (tr != NULL && tr->last_response != NULL + && MSG_IS_STATUS_1XX (tr->last_response)) + { + i = generating_cancel (&request, tr->orig_request); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot terminate this call!\n")); + return -2; + } + i = eXosip_create_cancel_transaction (jc, jd, request); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot initiate SIP transaction!\n")); + return i; + } + if (jd != NULL) + { + osip_dialog_free (jd->d_dialog); + jd->d_dialog = NULL; + eXosip_update(); //AMD 30/09/05 + } + return 0; + } + + if (jd == NULL || jd->d_dialog == NULL) + { + /* Check if some dialog exists */ + if (jd != NULL && jd->d_dialog != NULL) + { + transport = NULL; + if (tr!=NULL && tr->orig_request!=NULL) + transport = _eXosip_transport_protocol(tr->orig_request); + if (transport==NULL) + i = generating_bye (&request, jd->d_dialog, "UDP"); + else + i = generating_bye (&request, jd->d_dialog, transport); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot terminate this call!\n")); + return -2; + } + + if (jc->response_auth!=NULL) + eXosip_add_authentication_information (request, jc->response_auth); + + i = eXosip_create_transaction (jc, jd, request); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot initiate SIP transaction!\n")); + return -2; + } + + osip_dialog_free (jd->d_dialog); + jd->d_dialog = NULL; + eXosip_update(); //AMD 30/09/05 + return 0; + } + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No established dialog!\n")); + return -1; + } + + if (tr == NULL) + { + /*this may not be enough if it's a re-INVITE! */ + tr = eXosip_find_last_inc_invite (jc, jd); + if (tr != NULL && tr->last_response != NULL && + MSG_IS_STATUS_1XX (tr->last_response)) + { /* answer with 603 */ + i = eXosip_call_send_answer (tr->transactionid, 603, NULL); + return i; + } + } + + transport = NULL; + if (tr!=NULL && tr->orig_request!=NULL) + transport = _eXosip_transport_protocol(tr->orig_request); + if (transport==NULL) + i = generating_bye (&request, jd->d_dialog, "UDP"); + else + i = generating_bye (&request, jd->d_dialog, transport); + + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot terminate this call!\n")); + return -2; + } + if (jc->response_auth!=NULL) + eXosip_add_authentication_information (request, jc->response_auth); + + i = eXosip_create_transaction (jc, jd, request); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot initiate SIP transaction!\n")); + return -2; + } + + osip_dialog_free (jd->d_dialog); + jd->d_dialog = NULL; + eXosip_update(); //AMD 30/09/05 + return 0; +} + +int +eXosip_call_build_prack (int tid, osip_message_t ** prack) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + osip_transaction_t *tr = NULL; + + osip_header_t *rseq; + char *transport; + int i; + + *prack = NULL; + + if (tid > 0) + { + _eXosip_call_transaction_find (tid, &jc, &jd, &tr); + } + if (jc == NULL || jd == NULL || jd->d_dialog == NULL + || tr == NULL || tr->orig_request == NULL + || tr->orig_request->sip_method == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here or no transaction for call\n")); + return -1; + } + + if (0 != osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) + return -1; + + /* PRACK are only send in the PROCEEDING state */ + if (tr->state != ICT_PROCEEDING) + return -1; + + if (tr->orig_request->cseq == NULL + || tr->orig_request->cseq->number == NULL + || tr->orig_request->cseq->method == NULL) + return -1; + + transport = NULL; + if (tr!=NULL && tr->orig_request!=NULL) + transport = _eXosip_transport_protocol(tr->orig_request); + + if (transport==NULL) + i = _eXosip_build_request_within_dialog (prack, "PRACK", jd->d_dialog, "UDP"); + else + i = _eXosip_build_request_within_dialog (prack, "PRACK", jd->d_dialog, transport); + + if (i != 0) + return -2; + + osip_message_header_get_byname (tr->last_response, "RSeq", 0, &rseq); + if (rseq != NULL && rseq->hvalue != NULL) + { + char tmp[128]; + + memset (tmp, '\0', sizeof (tmp)); + snprintf (tmp, 127, "%s %s %s", rseq->hvalue, + tr->orig_request->cseq->number, tr->orig_request->cseq->method); + osip_message_set_header (*prack, "RAck", tmp); + } + + return 0; +} + +int +eXosip_call_send_prack (int tid, osip_message_t * prack) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + osip_transaction_t *tr = NULL; + + osip_event_t *sipevent; + int i; + + if (prack == NULL) + return -1; + + if (tid > 0) + { + _eXosip_call_transaction_find (tid, &jc, &jd, &tr); + } + if (jc == NULL || jd == NULL || jd->d_dialog == NULL + || tr == NULL || tr->orig_request == NULL + || tr->orig_request->sip_method == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here or no transaction for call\n")); + osip_message_free (prack); + return -1; + } + + if (0 != osip_strcasecmp (tr->orig_request->sip_method, "INVITE")) + { + osip_message_free (prack); + return -1; + } + + /* PRACK are only send in the PROCEEDING state */ + if (tr->state != ICT_PROCEEDING) + { + osip_message_free (prack); + return -1; + } + + tr = NULL; + i = osip_transaction_init (&tr, NICT, eXosip.j_osip, prack); + + if (i != 0) + { + osip_message_free (prack); + return -2; + } + + osip_list_add (jd->d_out_trs, tr, 0); + + sipevent = osip_new_outgoing_sipmessage (prack); + sipevent->transactionid = tr->transactionid; + + osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (jc, jd, NULL, NULL)); + osip_transaction_add_event (tr, sipevent); + __eXosip_wakeup (); + return 0; +} + + +int +_eXosip_call_redirect_request (eXosip_call_t * jc, + eXosip_dialog_t * jd, osip_transaction_t * out_tr) +{ + osip_transaction_t *tr = NULL; + osip_message_t *msg = NULL; + osip_event_t *sipevent; + + char locip[256]; + int cseq; + char tmp[256]; + osip_via_t *via; + osip_contact_t *co; + int pos; + int i; + int protocol = IPPROTO_UDP; + + if (jc == NULL) + return -1; + if (jd != NULL) + { + if (jd->d_out_trs == NULL) + return -1; + } + if (out_tr == NULL + || out_tr->orig_request == NULL || out_tr->last_response == NULL) + return -1; + + osip_message_clone (out_tr->orig_request, &msg); + if (msg == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for authentication\n")); + return -1; + } + + via = (osip_via_t *) osip_list_get (msg->vias, 0); + if (via == NULL || msg->cseq == NULL || msg->cseq->number == NULL) + { + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: missing via or cseq header\n")); + return -1; + } + + co = NULL; + pos = 0; + while (!osip_list_eol (out_tr->last_response->contacts, pos)) + { + co = (osip_contact_t *) osip_list_get (out_tr->last_response->contacts, pos); + if (co != NULL && co->url != NULL && co->url->url_params != NULL) + { + /* check tranport? Only allow UDP, right now */ + osip_uri_param_t *u_param; + int pos2; + + u_param = NULL; + pos2 = 0; + while (!osip_list_eol (co->url->url_params, pos2)) + { + u_param = + (osip_uri_param_t *) osip_list_get (co->url->url_params, pos2); + if (u_param == NULL || u_param->gname == NULL + || u_param->gvalue == NULL) + { + u_param = NULL; + /* skip */ + } else if (0 == osip_strcasecmp (u_param->gvalue, "transport")) + { + if (0 == osip_strcasecmp (u_param->gvalue, "udp")) + { +#if 0 + /* remove the UDP parameter */ + osip_list_remove (co->url->url_params, pos2); + osip_uri_param_free (u_param); +#endif + u_param = NULL; + protocol=IPPROTO_UDP; + break; /* ok */ + } + else if (0 == osip_strcasecmp (u_param->gvalue, "tcp")) + { +#if 0 + osip_list_remove (co->url->url_params, pos2); + osip_uri_param_free (u_param); +#endif + protocol=IPPROTO_TCP; + u_param = NULL; + } + break; + } + pos2++; + } + + if (u_param == NULL || u_param->gname == NULL || u_param->gvalue == NULL) + { + break; /* default is udp! */ + } + } + pos++; + co = NULL; + } + + if (co == NULL || co->url == NULL) + { + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: contact header\n")); + return -1; + } + + /* TODO: + remove extra parameter from new request-uri + check usual parameter like "transport" + */ + + /* replace request-uri with NEW contact address */ + osip_uri_free (msg->req_uri); + msg->req_uri = NULL; + osip_uri_clone (co->url, &msg->req_uri); + + /* increment cseq */ + cseq = atoi (msg->cseq->number); + osip_free (msg->cseq->number); + msg->cseq->number = strdup_printf ("%i", cseq + 1); + if (jd != NULL && jd->d_dialog != NULL) + { + jd->d_dialog->local_cseq++; + } + + osip_list_remove (msg->vias, 0); + osip_via_free (via); + + if (protocol==IPPROTO_UDP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, + sizeof (locip)); + if (eXosip.net_interfaces[0].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/UDP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/UDP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, via_branch_new_random ()); + } + else if (protocol==IPPROTO_TCP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[1].net_ip_family, locip, + sizeof (locip)); + if (eXosip.net_interfaces[1].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/TCP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/TCP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, via_branch_new_random ()); + } + else + { + /* tls? */ + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol\n")); + return -1; + } + + osip_via_init (&via); + osip_via_parse (via, tmp); + osip_list_add (msg->vias, via, 0); + + eXosip_add_authentication_information (msg, out_tr->last_response); + osip_message_force_update (msg); + + if (0 != osip_strcasecmp (msg->sip_method, "INVITE")) + { + i = osip_transaction_init (&tr, NICT, eXosip.j_osip, msg); + } else + { + i = osip_transaction_init (&tr, ICT, eXosip.j_osip, msg); + } + + if (i != 0) + { + osip_message_free (msg); + return -1; + } + + if (out_tr == jc->c_out_tr) + { + /* replace with the new tr */ + osip_list_add (eXosip.j_transactions, jc->c_out_tr, 0); + jc->c_out_tr = tr; + + /* fix dialog issue */ + if (jd!=NULL) + { + REMOVE_ELEMENT(jc->c_dialogs, jd); + eXosip_dialog_free(jd); + jd=NULL; + } + } else + { + /* add the new tr for the current dialog */ + osip_list_add (jd->d_out_trs, tr, 0); + } + + sipevent = osip_new_outgoing_sipmessage (msg); + + osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (jc, jd, NULL, NULL)); + osip_transaction_add_event (tr, sipevent); + + eXosip_update (); /* fixed? */ + __eXosip_wakeup (); + return 0; +} + +int +_eXosip_call_send_request_with_credential (eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_transaction_t * out_tr) +{ + osip_transaction_t *tr = NULL; + osip_message_t *msg = NULL; + osip_event_t *sipevent; + + char locip[256]; + int cseq; + char tmp[256]; + osip_via_t *via; + int i; + int pos; + + if (jc == NULL) + return -1; + if (jd != NULL) + { + if (jd->d_out_trs == NULL) + return -1; + } + if (out_tr == NULL + || out_tr->orig_request == NULL || out_tr->last_response == NULL) + return -1; + + osip_message_clone (out_tr->orig_request, &msg); + if (msg == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for authentication\n")); + return -1; + } + + /* remove all previous authentication headers */ + pos=0; + while (!osip_list_eol(msg->authorizations, pos)) + { + osip_authorization_t *auth; + auth = (osip_authorization_t*)osip_list_get(msg->authorizations, pos); + osip_list_remove(msg->authorizations, pos); + osip_authorization_free(auth); + pos++; + } + + pos=0; + while (!osip_list_eol(msg->proxy_authorizations, pos)) + { + osip_proxy_authorization_t *auth; + auth = (osip_proxy_authorization_t*)osip_list_get(msg->proxy_authorizations, pos); + osip_list_remove(msg->proxy_authorizations, pos); + osip_authorization_free(auth); + pos++; + } + + + via = (osip_via_t *) osip_list_get (msg->vias, 0); + if (via == NULL || msg->cseq == NULL || msg->cseq->number == NULL) + { + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: missing via or cseq header\n")); + return -1; + } + + /* increment cseq */ + cseq = atoi (msg->cseq->number); + osip_free (msg->cseq->number); + msg->cseq->number = strdup_printf ("%i", cseq + 1); + if (jd != NULL && jd->d_dialog != NULL) + { + jd->d_dialog->local_cseq++; + } + + osip_list_remove (msg->vias, 0); + osip_via_free (via); + i = _eXosip_find_protocol(out_tr->orig_request); + if (i==IPPROTO_UDP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, + sizeof (locip)); + if (eXosip.net_interfaces[0].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/UDP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/UDP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, via_branch_new_random ()); + } + else if (i==IPPROTO_TCP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[1].net_ip_family, locip, + sizeof (locip)); + if (eXosip.net_interfaces[1].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/TCP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/TCP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, via_branch_new_random ()); + } + else + { + /* tls? */ + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol\n")); + return -1; + } + + osip_via_init (&via); + osip_via_parse (via, tmp); + osip_list_add (msg->vias, via, 0); + + eXosip_add_authentication_information (msg, out_tr->last_response); + osip_message_force_update (msg); + + if (0 != osip_strcasecmp (msg->sip_method, "INVITE")) + { + i = osip_transaction_init (&tr, NICT, eXosip.j_osip, msg); + } else + { + i = osip_transaction_init (&tr, ICT, eXosip.j_osip, msg); + } + + if (i != 0) + { + osip_message_free (msg); + return -1; + } + + if (out_tr == jc->c_out_tr) + { + /* replace with the new tr */ + osip_list_add (eXosip.j_transactions, jc->c_out_tr, 0); + jc->c_out_tr = tr; + + /* fix dialog issue */ + if (jd!=NULL) + { + REMOVE_ELEMENT(jc->c_dialogs, jd); + eXosip_dialog_free(jd); + jd=NULL; + } + } else + { + /* add the new tr for the current dialog */ + osip_list_add (jd->d_out_trs, tr, 0); + } + + sipevent = osip_new_outgoing_sipmessage (msg); + + osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (jc, jd, NULL, NULL)); + osip_transaction_add_event (tr, sipevent); + + eXosip_update (); /* fixed? */ + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/eXconf.c b/exosip2/eXconf.c new file mode 100644 index 0000000000000000000000000000000000000000..2e89e3ae209df08985e8db69167b099e3d29b9d4 --- /dev/null +++ b/exosip2/eXconf.c @@ -0,0 +1,803 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" +#include <eXosip2/eXosip.h> + +#include <osip2/osip_mt.h> +#include <osip2/osip_condv.h> + +extern eXosip_t eXosip; + +int ipv6_enable = 0; + +static void *_eXosip_thread (void *arg); +static int _eXosip_execute (void); +static void _eXosip_keep_alive(void); + +void +eXosip_enable_ipv6 (int _ipv6_enable) +{ + ipv6_enable = _ipv6_enable; +} + +void +eXosip_masquerade_contact (const char *public_address, int port) +{ + if (public_address == NULL || public_address[0] == '\0') + { + memset (eXosip.net_interfaces[0].net_firewall_ip, '\0', + sizeof (eXosip.net_interfaces[0].net_firewall_ip)); + memset (eXosip.net_interfaces[1].net_firewall_ip, '\0', + sizeof (eXosip.net_interfaces[1].net_firewall_ip)); + memset (eXosip.net_interfaces[2].net_firewall_ip, '\0', + sizeof (eXosip.net_interfaces[2].net_firewall_ip)); + return; + } + + snprintf (eXosip.net_interfaces[0].net_firewall_ip, + sizeof (eXosip.net_interfaces[0].net_firewall_ip), "%s", + public_address); + snprintf (eXosip.net_interfaces[1].net_firewall_ip, + sizeof (eXosip.net_interfaces[1].net_firewall_ip), "%s", + public_address); + snprintf (eXosip.net_interfaces[2].net_firewall_ip, + sizeof (eXosip.net_interfaces[2].net_firewall_ip), "%s", + public_address); + + if (port>0) + { + snprintf (eXosip.net_interfaces[0].net_port, + sizeof (eXosip.net_interfaces[0].net_port), "%i", port); + snprintf (eXosip.net_interfaces[1].net_port, + sizeof (eXosip.net_interfaces[1].net_port), "%i", port); + snprintf (eXosip.net_interfaces[2].net_port, + sizeof (eXosip.net_interfaces[2].net_port), "%i", port); + } + return; +} + +int +eXosip_force_masquerade_contact (const char *public_address) +{ + if (public_address == NULL || public_address[0] == '\0') + { + memset (eXosip.net_interfaces[0].net_firewall_ip, '\0', + sizeof (eXosip.net_interfaces[0].net_firewall_ip)); + memset (eXosip.net_interfaces[1].net_firewall_ip, '\0', + sizeof (eXosip.net_interfaces[1].net_firewall_ip)); + memset (eXosip.net_interfaces[2].net_firewall_ip, '\0', + sizeof (eXosip.net_interfaces[2].net_firewall_ip)); + eXosip.forced_localip = 0; + return 0; + } + eXosip.forced_localip = 1; + snprintf (eXosip.net_interfaces[0].net_firewall_ip, 50, "%s", public_address); + snprintf (eXosip.net_interfaces[1].net_firewall_ip, 50, "%s", public_address); + snprintf (eXosip.net_interfaces[2].net_firewall_ip, 50, "%s", public_address); + return 0; +} + +int +eXosip_guess_localip (int family, char *address, int size) +{ + return eXosip_guess_ip_for_via (family, address, size); +} + +int +eXosip_is_public_address (const char *c_address) +{ + return (0 != strncmp (c_address, "192.168", 7) + && 0 != strncmp (c_address, "10.", 3) + && 0 != strncmp (c_address, "172.16.", 7) + && 0 != strncmp (c_address, "172.17.", 7) + && 0 != strncmp (c_address, "172.18.", 7) + && 0 != strncmp (c_address, "172.19.", 7) + && 0 != strncmp (c_address, "172.20.", 7) + && 0 != strncmp (c_address, "172.21.", 7) + && 0 != strncmp (c_address, "172.22.", 7) + && 0 != strncmp (c_address, "172.23.", 7) + && 0 != strncmp (c_address, "172.24.", 7) + && 0 != strncmp (c_address, "172.25.", 7) + && 0 != strncmp (c_address, "172.26.", 7) + && 0 != strncmp (c_address, "172.27.", 7) + && 0 != strncmp (c_address, "172.28.", 7) + && 0 != strncmp (c_address, "172.29.", 7) + && 0 != strncmp (c_address, "172.30.", 7) + && 0 != strncmp (c_address, "172.31.", 7) + && 0 != strncmp (c_address, "169.254", 7)); +} + +void +eXosip_set_user_agent (const char *user_agent) +{ + osip_free (eXosip.user_agent); + eXosip.user_agent = osip_strdup (user_agent); +} + +void +eXosip_kill_transaction (osip_list_t * transactions) +{ + osip_transaction_t *transaction; + + if (!osip_list_eol (transactions, 0)) + { + /* some transaction are still used by osip, + transaction should be released by modules! */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "module sfp: _osip_kill_transaction transaction should be released by modules!\n")); + } + + while (!osip_list_eol (transactions, 0)) + { + transaction = osip_list_get (transactions, 0); + + __eXosip_delete_jinfo (transaction); + osip_transaction_free (transaction); + } +} + +void +eXosip_quit (void) +{ + jauthinfo_t *jauthinfo; + eXosip_call_t *jc; + eXosip_notify_t *jn; + eXosip_subscribe_t *js; + eXosip_reg_t *jreg; + eXosip_pub_t *jpub; + int i; + int pos; + + eXosip.j_stop_ua = 1; /* ask to quit the application */ + __eXosip_wakeup (); + __eXosip_wakeup_event (); + + i = osip_thread_join ((struct osip_thread *) eXosip.j_thread); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: can't terminate thread!\n")); + } + osip_free ((struct osip_thread *) eXosip.j_thread); + + jpipe_close (eXosip.j_socketctl); + jpipe_close (eXosip.j_socketctl_event); + + osip_free (eXosip.user_agent); + + for (jc = eXosip.j_calls; jc != NULL; jc = eXosip.j_calls) + { + REMOVE_ELEMENT (eXosip.j_calls, jc); + eXosip_call_free (jc); + } + + for (js = eXosip.j_subscribes; js != NULL; js = eXosip.j_subscribes) + { + REMOVE_ELEMENT (eXosip.j_subscribes, js); + eXosip_subscribe_free (js); + } + + for (jn = eXosip.j_notifies; jn != NULL; jn = eXosip.j_notifies) + { + REMOVE_ELEMENT (eXosip.j_notifies, jn); + eXosip_notify_free (jn); + } + + osip_mutex_destroy ((struct osip_mutex *) eXosip.j_mutexlock); + osip_cond_destroy ((struct osip_cond *) eXosip.j_cond); + + if (eXosip.net_interfaces[0].net_socket) + { + close (eXosip.net_interfaces[0].net_socket); + eXosip.net_interfaces[0].net_socket = -1; + } + if (eXosip.net_interfaces[1].net_socket) + { + close (eXosip.net_interfaces[1].net_socket); + eXosip.net_interfaces[1].net_socket = -1; + } + if (eXosip.net_interfaces[2].net_socket) + { + close (eXosip.net_interfaces[2].net_socket); + eXosip.net_interfaces[2].net_socket = -1; + } + + for (pos=0; pos<EXOSIP_MAX_SOCKETS; pos++) + { + if (eXosip.net_interfaces[0].net_socket_tab[pos].socket!=0) + close (eXosip.net_interfaces[0].net_socket_tab[pos].socket); + if (eXosip.net_interfaces[1].net_socket_tab[pos].socket!=0) + close (eXosip.net_interfaces[1].net_socket_tab[pos].socket); + if (eXosip.net_interfaces[2].net_socket_tab[pos].socket!=0) + close (eXosip.net_interfaces[2].net_socket_tab[pos].socket); + } + + for (jreg = eXosip.j_reg; jreg != NULL; jreg = eXosip.j_reg) + { + REMOVE_ELEMENT (eXosip.j_reg, jreg); + eXosip_reg_free (jreg); + } + + for (jpub = eXosip.j_pub; jpub != NULL; jpub = eXosip.j_pub) + { + REMOVE_ELEMENT (eXosip.j_pub, jpub); + _eXosip_pub_free (jpub); + } + + while (!osip_list_eol (eXosip.j_transactions, 0)) + { + osip_transaction_t *tr = + (osip_transaction_t *) osip_list_get (eXosip.j_transactions, 0); + if (tr->state == IST_TERMINATED || tr->state == ICT_TERMINATED + || tr->state == NICT_TERMINATED || tr->state == NIST_TERMINATED) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Release a terminated transaction\n")); + osip_list_remove (eXosip.j_transactions, 0); + __eXosip_delete_jinfo (tr); + osip_transaction_free (tr); + } else + { + osip_list_remove (eXosip.j_transactions, 0); + __eXosip_delete_jinfo (tr); + osip_transaction_free (tr); + } + } + + osip_free (eXosip.j_transactions); + + eXosip_kill_transaction (eXosip.j_osip->osip_ict_transactions); + eXosip_kill_transaction (eXosip.j_osip->osip_nict_transactions); + eXosip_kill_transaction (eXosip.j_osip->osip_ist_transactions); + eXosip_kill_transaction (eXosip.j_osip->osip_nist_transactions); + osip_release (eXosip.j_osip); + + { + eXosip_event_t *ev; + + for (ev = osip_fifo_tryget (eXosip.j_events); ev != NULL; + ev = osip_fifo_tryget (eXosip.j_events)) + eXosip_event_free (ev); + } + + osip_fifo_free (eXosip.j_events); + + for (jauthinfo = eXosip.authinfos; jauthinfo != NULL; + jauthinfo = eXosip.authinfos) + { + REMOVE_ELEMENT (eXosip.authinfos, jauthinfo); + osip_free (jauthinfo); + } + + return; +} + +int eXosip_set_socket(int transport, int socket, int port) +{ + if (eXosip.net_interfaces[0].net_socket>0) + close(eXosip.net_interfaces[0].net_socket); + + eXosip.net_interfaces[0].net_socket = socket; + snprintf (eXosip.net_interfaces[0].net_port, + sizeof (eXosip.net_interfaces[0].net_port), "%i", port); + + eXosip.j_thread = (void *) osip_thread_create (20000, _eXosip_thread, NULL); + if (eXosip.j_thread == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot start thread!\n")); + return -1; + } + return 0; +} + +#ifdef IPV6_V6ONLY +int setsockopt_ipv6only (int sock) +{ + int on = 1; + + return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (char *)&on, sizeof(on)); +} +#endif /* IPV6_V6ONLY */ + +int +eXosip_listen_addr (int transport, const char *addr, int port, int family, + int secure) +{ + int res; + struct addrinfo *addrinfo = NULL; + struct addrinfo *curinfo; + const char *node = addr; + int sock = -1; + struct eXosip_net *net_int; + char localip[256]; + + if (transport==IPPROTO_UDP) + net_int = &eXosip.net_interfaces[0]; + else if (transport==IPPROTO_TCP) + net_int = &eXosip.net_interfaces[1]; + else if (transport==IPPROTO_TCP && secure != 0) + net_int = &eXosip.net_interfaces[2]; + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unknown protocol (use IPPROTO_UDP or IPPROTO_TCP!\n")); + return -1; + } + + if (eXosip.http_port) + { + /* USE TUNNEL CAPABILITY */ + transport=IPPROTO_TCP; + } + + if (port < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: port must be higher than 0!\n")); + return -1; + } + + net_int->net_ip_family = family; + if (family == AF_INET6) + { + ipv6_enable = 1; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "IPv6 is enabled. Pls report bugs\n")); + } + + eXosip_guess_localip (net_int->net_ip_family, localip, + sizeof (localip)); + if (localip[0] == '\0') + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No ethernet interface found!\n")); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: using 127.0.0.1 (debug mode)!\n")); + /* we should always fallback on something. The linphone user will surely + start linphone BEFORE setting its dial up connection. */ + } + + if (!node) { + node = ipv6_enable ? "::" : "0.0.0.0"; + } + + + res = eXosip_get_addrinfo(&addrinfo, node, port, transport); + if (res) + return -1; + + for (curinfo = addrinfo; curinfo; curinfo = curinfo->ai_next) + { + socklen_t len; + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: address for protocol %d (search %d)\n", + curinfo->ai_protocol, transport)); + if (curinfo->ai_protocol && curinfo->ai_protocol != transport) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: Skipping protocol %d\n", + curinfo->ai_protocol)); + continue; + } + + sock = (int)socket(curinfo->ai_family, curinfo->ai_socktype, + curinfo->ai_protocol); + if (sock < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot create socket!\n", + strerror(errno))); + continue; + } + + if (eXosip.http_port) + { + break; + } + + if (curinfo->ai_family == AF_INET6) + { +#ifdef IPV6_V6ONLY + if (setsockopt_ipv6only(sock)) + { + close(sock); + sock = -1; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot set socket option!\n", + strerror(errno))); + continue; + } +#endif /* IPV6_V6ONLY */ + } + + res = bind (sock, curinfo->ai_addr, curinfo->ai_addrlen); + if (res < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot bind socket node:%s family:%d %s\n", + node, curinfo->ai_family, strerror(errno))); + close(sock); + sock = -1; + continue; + } + len = sizeof(net_int->ai_addr); + res = getsockname(sock, (struct sockaddr*)&net_int->ai_addr, + &len ); + if (res!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot get socket name (%s)\n", + strerror(errno))); + memcpy(&net_int->ai_addr, curinfo->ai_addr, curinfo->ai_addrlen); + } + + if (transport!=IPPROTO_UDP) + { + res = listen(sock, SOMAXCONN); + if (res < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot bind socket node:%s family:%d %s\n", + node, curinfo->ai_family, strerror(errno))); + close(sock); + sock = -1; + continue; + } + } + + break; + } + + freeaddrinfo(addrinfo); + + if (sock < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot bind on port: %i\n", + port)); + return -1; + } + + if (eXosip.http_port) + net_int->net_protocol = IPPROTO_UDP; + else + net_int->net_protocol = transport; + net_int->net_socket = sock; + + if (port==0) + { + /* get port number from socket */ + if (ipv6_enable == 0) + port = ntohs (((struct sockaddr_in*)&net_int->ai_addr)->sin_port); + else + port = ntohs (((struct sockaddr_in6*)&net_int->ai_addr)->sin6_port); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: Binding on port %i!\n", port)); + } + + snprintf (net_int->net_port, + sizeof (net_int->net_port) - 1, "%i", port); + + + + if (eXosip.http_port) + { + /* only ipv4 */ + struct sockaddr_in _addr; + char http_req[2048]; + char http_reply[2048]; + int len; + _addr.sin_port = (unsigned short) htons(eXosip.http_port); + _addr.sin_addr.s_addr = inet_addr(eXosip.http_proxy); + _addr.sin_family = PF_INET; + + if (connect(net_int->net_socket, (struct sockaddr *) &_addr, sizeof(_addr)) == -1) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: Failed to connect to http server on %s:%i!\n", eXosip.http_proxy, port)); + return -1; + } + + sprintf(http_req, "GET / HTTP/1.1\r\nUdpHost: %s:%d\r\n\r\n", eXosip.http_outbound_proxy, 5060); + + len = send(net_int->net_socket, http_req, (int) strlen(http_req), 0); + + if (len < 0) + return -1; + + osip_usleep(50000); + + if ((len = recv(net_int->net_socket, http_reply, sizeof(http_reply), 0)) > 0) + http_reply[len] = '\0'; + else + return -1; + + if (strncmp(http_reply, "HTTP/1.0 200 OK\r\n", 17) == 0 || strncmp(http_reply, "HTTP/1.1 200 OK\r\n", 17) == 0) + { + } + else + return -1; + } + + eXosip.j_thread = (void *) osip_thread_create (20000, _eXosip_thread, NULL); + if (eXosip.j_thread == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot start thread!\n")); + return -1; + } + return 0; +} + +int +eXosip_init (void) +{ + osip_t *osip; + + memset (&eXosip, 0, sizeof (eXosip)); + +#ifdef WIN32 + /* Initializing windows socket library */ + { + WORD wVersionRequested; + WSADATA wsaData; + int i; + + wVersionRequested = MAKEWORD (1, 1); + i = WSAStartup (wVersionRequested, &wsaData); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_WARNING, NULL, + "eXosip: Unable to initialize WINSOCK, reason: %d\n", i)); + /* return -1; It might be already initilized?? */ + } + } +#endif + + eXosip.user_agent = osip_strdup ("eXosip/" EXOSIP_VERSION); + + eXosip.j_calls = NULL; + eXosip.j_stop_ua = 0; + eXosip.j_thread = NULL; + eXosip.j_transactions = (osip_list_t *) osip_malloc (sizeof (osip_list_t)); + osip_list_init (eXosip.j_transactions); + eXosip.j_reg = NULL; + + eXosip.j_cond = (struct osip_cond *) osip_cond_init (); + + eXosip.j_mutexlock = (struct osip_mutex *) osip_mutex_init (); + + if (-1 == osip_init (&osip)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Cannot initialize osip!\n")); + return -1; + } + + osip_set_application_context (osip, &eXosip); + + eXosip_set_callbacks (osip); + + eXosip.j_osip = osip; + + /* open a TCP socket to wake up the application when needed. */ + eXosip.j_socketctl = jpipe (); + if (eXosip.j_socketctl == NULL) + return -1; + + eXosip.j_socketctl_event = jpipe (); + if (eXosip.j_socketctl_event == NULL) + return -1; + + /* To be changed in osip! */ + eXosip.j_events = (osip_fifo_t *) osip_malloc (sizeof (osip_fifo_t)); + osip_fifo_init (eXosip.j_events); + + return 0; +} + + +static int +_eXosip_execute (void) +{ + struct timeval lower_tv; + int i; + + osip_timers_gettimeout (eXosip.j_osip, &lower_tv); + if (lower_tv.tv_sec > 15) + { + lower_tv.tv_sec = 15; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: Reseting timer to 15s before waking up!\n")); + } else + { + /* add a small amount of time on windows to avoid + waking up too early. (probably a bad time precision) */ + if (lower_tv.tv_usec<900000) + lower_tv.tv_usec = 100000; /* add 10ms */ + else + { + lower_tv.tv_usec = 10000; /* add 10ms */ + lower_tv.tv_sec++; + } + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: timer sec:%i usec:%i!\n", + lower_tv.tv_sec, lower_tv.tv_usec)); + } + i = eXosip_read_message (1, lower_tv.tv_sec, lower_tv.tv_usec); + + if (i == -2) + { + return -2; + } + + eXosip_lock (); + osip_timers_ict_execute (eXosip.j_osip); + osip_timers_nict_execute (eXosip.j_osip); + osip_timers_ist_execute (eXosip.j_osip); + osip_timers_nist_execute (eXosip.j_osip); + + osip_ict_execute (eXosip.j_osip); + osip_nict_execute (eXosip.j_osip); + osip_ist_execute (eXosip.j_osip); + osip_nist_execute (eXosip.j_osip); + + /* free all Calls that are in the TERMINATED STATE? */ + eXosip_release_terminated_calls (); + eXosip_release_terminated_registrations (); + + eXosip_unlock (); + + + if (eXosip.keep_alive>0) + { + _eXosip_keep_alive(); + } + + return 0; +} + +int eXosip_set_option(eXosip_option opt, void *value) +{ + int val; + char *tmp; + switch (opt) { + case EXOSIP_OPT_UDP_KEEP_ALIVE: + val = *((int*)value); + eXosip.keep_alive = val; /* value in ms */ + break; + case EXOSIP_OPT_UDP_LEARN_PORT: + val = *((int*)value); + eXosip.learn_port = val; /* value in ms */ + break; + case EXOSIP_OPT_SET_HTTP_TUNNEL_PORT: + val = *((int*)value); + eXosip.http_port = val; /* value in ms */ + break; + case EXOSIP_OPT_SET_HTTP_TUNNEL_PROXY: + tmp = (char*)value; + memset(eXosip.http_proxy, '\0', sizeof(eXosip.http_proxy)); + if (tmp!=NULL && tmp[0]!='\0') + strncpy(eXosip.http_proxy, tmp, sizeof(eXosip.http_proxy)); /* value in proxy:port */ + break; + case EXOSIP_OPT_SET_HTTP_OUTBOUND_PROXY: + tmp = (char*)value; + memset(eXosip.http_outbound_proxy, '\0', sizeof(eXosip.http_outbound_proxy)); + if (tmp!=NULL && tmp[0]!='\0') + strncpy(eXosip.http_outbound_proxy, tmp, sizeof(eXosip.http_outbound_proxy)); /* value in proxy:port */ + break; + + } + return 0; +} + +static void +_eXosip_keep_alive(void) +{ + static struct timeval mtimer = { 0, 0 }; + + eXosip_reg_t *jr; + struct eXosip_net *net; + char buf[4] = "jaK"; + struct timeval now; + osip_gettimeofday (&now, NULL); + + if (mtimer.tv_sec==0 && mtimer.tv_usec==0) + { + /* first init */ + osip_gettimeofday (&mtimer, NULL); + add_gettimeofday (&mtimer, eXosip.keep_alive); + } + + if (osip_timercmp (&now, &mtimer, <)) + { + return; /* not yet time */ + } + + /* reset timer */ + osip_gettimeofday (&mtimer, NULL); + add_gettimeofday (&mtimer, eXosip.keep_alive); + + net = &eXosip.net_interfaces[0]; + if (net == NULL) + { + return ; + } + + for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) + { + if (jr->len>0) + { + if (sendto (net->net_socket, (const void *) buf, 4, 0, + (struct sockaddr *) &(jr->addr), jr->len )>0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: Keep Alive sent on UDP!\n")); + } + } + } +} + +void * +_eXosip_thread (void *arg) +{ + int i; + + while (eXosip.j_stop_ua == 0) + { + i = _eXosip_execute (); + if (i == -2) + osip_thread_exit (); + } + osip_thread_exit (); + return NULL; +} + diff --git a/exosip2/eXinsubscription_api.c b/exosip2/eXinsubscription_api.c new file mode 100644 index 0000000000000000000000000000000000000000..973cfef6c10b5ea71f8a69224ebdf99377ea26db --- /dev/null +++ b/exosip2/eXinsubscription_api.c @@ -0,0 +1,567 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +static int _eXosip_insubscription_transaction_find (int tid, + eXosip_notify_t ** jn, + eXosip_dialog_t ** jd, + osip_transaction_t ** tr); + +static int +_eXosip_insubscription_transaction_find (int tid, eXosip_notify_t ** jn, + eXosip_dialog_t ** jd, + osip_transaction_t ** tr) +{ + for (*jn = eXosip.j_notifies; *jn != NULL; *jn = (*jn)->next) + { + if ((*jn)->n_inc_tr != NULL && (*jn)->n_inc_tr->transactionid == tid) + { + *tr = (*jn)->n_inc_tr; + *jd = (*jn)->n_dialogs; + return 0; + } + if ((*jn)->n_out_tr != NULL && (*jn)->n_out_tr->transactionid == tid) + { + *tr = (*jn)->n_out_tr; + *jd = (*jn)->n_dialogs; + return 0; + } + for (*jd = (*jn)->n_dialogs; *jd != NULL; *jd = (*jd)->next) + { + osip_transaction_t *transaction; + int pos = 0; + + while (!osip_list_eol ((*jd)->d_inc_trs, pos)) + { + transaction = + (osip_transaction_t *) osip_list_get ((*jd)->d_inc_trs, pos); + if (transaction != NULL && transaction->transactionid == tid) + { + *tr = transaction; + return 0; + } + pos++; + } + + pos = 0; + while (!osip_list_eol ((*jd)->d_out_trs, pos)) + { + transaction = + (osip_transaction_t *) osip_list_get ((*jd)->d_out_trs, pos); + if (transaction != NULL && transaction->transactionid == tid) + { + *tr = transaction; + return 0; + } + pos++; + } + } + } + *jd = NULL; + *jn = NULL; + return -1; +} + +int +eXosip_insubscription_build_answer (int tid, int status, osip_message_t ** answer) +{ + int i = -1; + eXosip_dialog_t *jd = NULL; + eXosip_notify_t *jn = NULL; + osip_transaction_t *tr = NULL; + + *answer = NULL; + + if (tid > 0) + { + _eXosip_insubscription_transaction_find (tid, &jn, &jd, &tr); + } + if (tr == NULL || jd == NULL || jn == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No incoming subscription here?\n")); + return -1; + } + + if (status < 101 || status > 699) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (101<status<699)\n")); + return -1; + } + + if (jd != NULL) + i = + _eXosip_build_response_default (answer, jd->d_dialog, status, + tr->orig_request); + else + i = _eXosip_build_response_default (answer, NULL, status, tr->orig_request); + + if (i != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: Could not create response for %s\n", + tr->orig_request->sip_method)); + return -1; + } + + if (status >= 200 && status <= 299) + _eXosip_notify_add_expires_in_2XX_for_subscribe (jn, *answer); + + if (status < 300) + i = complete_answer_that_establish_a_dialog (*answer, tr->orig_request); + + return 0; +} + +int +eXosip_insubscription_send_answer (int tid, int status, osip_message_t * answer) +{ + int i = -1; + eXosip_dialog_t *jd = NULL; + eXosip_notify_t *jn = NULL; + osip_transaction_t *tr = NULL; + osip_event_t *evt_answer; + + if (tid > 0) + { + _eXosip_insubscription_transaction_find (tid, &jn, &jd, &tr); + } + if (jd == NULL || tr == NULL || tr->orig_request == NULL + || tr->orig_request->sip_method == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No incoming subscription here?\n")); + osip_message_free (answer); + return -1; + } + + if (answer == NULL) + { + if (0 == osip_strcasecmp (tr->orig_request->sip_method, "SUBSCRIBE")) + { + if (status >= 101 && status <= 199) + { + } else if (status >= 300 && status <= 699) + { + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: Wrong parameter?\n")); + return -1; + } + } + } + + /* is the transaction already answered? */ + if (tr->state == NIST_COMPLETED || tr->state == NIST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + osip_message_free (answer); + return -1; + } + + if (answer == NULL) + { + if (0 == osip_strcasecmp (tr->orig_request->sip_method, "SUBSCRIBE")) + { + if (status < 200) + i = _eXosip_insubscription_answer_1xx (jn, jd, status); + else + i = _eXosip_insubscription_answer_3456xx (jn, jd, status); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot send response!\n")); + return -1; + } + } else + { + /* TODO */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: a response must be given!\n")); + return -1; + } + return 0; + } else + { + i = 0; + } + + if (0 == osip_strcasecmp (tr->orig_request->sip_method, "SUBSCRIBE")) + { + if (MSG_IS_STATUS_1XX (answer)) + { + } else if (MSG_IS_STATUS_2XX (answer)) + { + eXosip_dialog_set_200ok (jd, answer); + osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED); + } else if (answer->status_code >= 300 && answer->status_code <= 699) + { + i = 0; + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (101<status<699)\n")); + osip_message_free (answer); + return -1; + } + if (i != 0) + { + osip_message_free (answer); + return -1; + } + } + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + eXosip_update (); + __eXosip_wakeup (); + return 0; +} + +int +eXosip_insubscription_build_notify (int did, int subscription_status, + int subscription_reason, + osip_message_t ** request) +{ + eXosip_dialog_t *jd = NULL; + eXosip_notify_t *jn = NULL; + + char subscription_state[50]; + char *tmp; + int now = time (NULL); + + int i; + + *request = NULL; + if (did > 0) + { + eXosip_notify_dialog_find (did, &jn, &jd); + } + if (jd == NULL || jn == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No incoming subscription here?\n")); + return -1; + } + + i = eXosip_insubscription_build_request (did, "NOTIFY", request); + if (i != 0) + { + return i; + } +#ifndef SUPPORT_MSN + if (subscription_status == EXOSIP_SUBCRSTATE_PENDING) + osip_strncpy (subscription_state, "pending;expires=", 16); + else if (subscription_status == EXOSIP_SUBCRSTATE_ACTIVE) + osip_strncpy (subscription_state, "active;expires=", 15); + else if (subscription_status == EXOSIP_SUBCRSTATE_TERMINATED) + { + if (subscription_reason == DEACTIVATED) + osip_strncpy (subscription_state, "terminated;reason=deactivated", 29); + else if (subscription_reason == PROBATION) + osip_strncpy (subscription_state, "terminated;reason=probation", 27); + else if (subscription_reason == REJECTED) + osip_strncpy (subscription_state, "terminated;reason=rejected", 26); + else if (subscription_reason == TIMEOUT) + osip_strncpy (subscription_state, "terminated;reason=timeout", 25); + else if (subscription_reason == GIVEUP) + osip_strncpy (subscription_state, "terminated;reason=giveup", 24); + else if (subscription_reason == NORESOURCE) + osip_strncpy (subscription_state, "terminated;reason=noresource", 28); + else + osip_strncpy (subscription_state, "terminated;reason=noresource", 28); + } else + osip_strncpy (subscription_state, "pending;expires=", 16); + + tmp = subscription_state + strlen (subscription_state); + if (subscription_status != EXOSIP_SUBCRSTATE_TERMINATED) + sprintf (tmp, "%i", jn->n_ss_expires - now); + osip_message_set_header (*request, "Subscription-State", subscription_state); +#endif + + return 0; +} + +int +eXosip_insubscription_build_request (int did, const char *method, + osip_message_t ** request) +{ + eXosip_dialog_t *jd = NULL; + eXosip_notify_t *jn = NULL; + + osip_transaction_t *transaction; + char *transport; + int i; + + *request = NULL; + if (method == NULL || method[0] == '\0') + return -1; + + if (did > 0) + { + eXosip_notify_dialog_find (did, &jn, &jd); + } + if (jd == NULL || jn == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No incoming subscription here?\n")); + return -1; + } + + transaction = NULL; + transaction = eXosip_find_last_out_notify (jn, jd); + if (transaction != NULL) + { + if (transaction->state != NICT_TERMINATED && + transaction->state != NIST_TERMINATED && + transaction->state != NICT_COMPLETED && + transaction->state != NIST_COMPLETED) + return -1; + } + + transport = NULL; + if (transaction==NULL) + transaction = jn->n_inc_tr; + + if (transaction!=NULL && transaction->orig_request!=NULL) + transport = _eXosip_transport_protocol(transaction->orig_request); + + transaction = NULL; + + if (transport==NULL) + i = _eXosip_build_request_within_dialog (request, method, jd->d_dialog, "UDP"); + else + i = _eXosip_build_request_within_dialog (request, method, jd->d_dialog, transport); + if (i != 0) + return -2; + + return 0; +} + +int +eXosip_insubscription_send_request (int did, osip_message_t * request) +{ + eXosip_dialog_t *jd = NULL; + eXosip_notify_t *jn = NULL; + + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + if (request == NULL) + return -1; + + if (did > 0) + { + eXosip_notify_dialog_find (did, &jn, &jd); + } + if (jd == NULL || jn == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No incoming subscription here?\n")); + osip_message_free (request); + return -1; + } + + transaction = NULL; + transaction = eXosip_find_last_out_notify (jn, jd); + if (transaction != NULL) + { + if (transaction->state != NICT_TERMINATED && + transaction->state != NIST_TERMINATED && + transaction->state != NICT_COMPLETED && + transaction->state != NIST_COMPLETED) + { + osip_message_free (request); + return -1; + } + transaction = NULL; + } + + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, request); + if (i != 0) + { + osip_message_free (request); + return -1; + } + + osip_list_add (jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage (request); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, jd, NULL, jn)); + osip_transaction_add_event (transaction, sipevent); + __eXosip_wakeup (); + return 0; +} + +int +_eXosip_insubscription_send_request_with_credential (eXosip_notify_t * jn, + eXosip_dialog_t * jd, + osip_transaction_t * out_tr) +{ + osip_transaction_t *tr = NULL; + osip_message_t *msg = NULL; + osip_event_t *sipevent; + + char locip[256]; + int cseq; + char tmp[256]; + osip_via_t *via; + int i; + + if (jn == NULL) + return -1; + if (jd != NULL) + { + if (jd->d_out_trs == NULL) + return -1; + } + + if (out_tr == NULL) + { + out_tr = eXosip_find_last_out_notify (jn, jd); + } + + if (out_tr == NULL + || out_tr->orig_request == NULL || out_tr->last_response == NULL) + return -1; + + osip_message_clone (out_tr->orig_request, &msg); + if (msg == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for authentication\n")); + return -1; + } + + via = (osip_via_t *) osip_list_get (msg->vias, 0); + if (via == NULL || msg->cseq == NULL || msg->cseq->number == NULL) + { + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: missing via or cseq header\n")); + return -1; + } + + /* increment cseq */ + cseq = atoi (msg->cseq->number); + osip_free (msg->cseq->number); + msg->cseq->number = strdup_printf ("%i", cseq + 1); + if (jd != NULL && jd->d_dialog != NULL) + { + jd->d_dialog->local_cseq++; + } + + osip_list_remove (msg->vias, 0); + osip_via_free (via); + + i = _eXosip_find_protocol(out_tr->orig_request); + if (i==IPPROTO_UDP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, + sizeof (locip)); + if (eXosip.net_interfaces[0].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/UDP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, + via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/UDP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, + via_branch_new_random ()); + } + else if (i==IPPROTO_TCP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[1].net_ip_family, locip, + sizeof (locip)); + if (eXosip.net_interfaces[1].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/TCP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, + via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/TCP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, + via_branch_new_random ()); + } + else + { + /* tls? */ + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol\n")); + return -1; + } + + osip_via_init (&via); + osip_via_parse (via, tmp); + osip_list_add (msg->vias, via, 0); + + eXosip_add_authentication_information (msg, out_tr->last_response); + osip_message_force_update (msg); + + i = osip_transaction_init (&tr, NICT, eXosip.j_osip, msg); + + if (i != 0) + { + osip_message_free (msg); + return -1; + } + + /* add the new tr for the current dialog */ + osip_list_add (jd->d_out_trs, tr, 0); + + sipevent = osip_new_outgoing_sipmessage (msg); + + osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (NULL, jd, NULL, jn)); + osip_transaction_add_event (tr, sipevent); + + eXosip_update (); /* fixed? */ + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/eXmessage_api.c b/exosip2/eXmessage_api.c new file mode 100644 index 0000000000000000000000000000000000000000..c21b649fffc954576478036e5c2fcabc3b35fdae --- /dev/null +++ b/exosip2/eXmessage_api.c @@ -0,0 +1,196 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +int +eXosip_message_build_request (osip_message_t ** message, const char *method, + const char *to, const char *from, const char *route) +{ + int i; + + *message = NULL; + if (method != NULL && *method == '\0') + return -1; + if (to != NULL && *to == '\0') + return -1; + if (from != NULL && *from == '\0') + return -1; + if (route != NULL && *route == '\0') + route = NULL; + + i = generating_request_out_of_dialog (message, method, to, "UDP", from, route); + if (i != 0) + return -1; + + return 0; +} + +int +eXosip_message_send_request (osip_message_t * message) +{ + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, message); + if (i != 0) + { + osip_message_free (message); + return -1; + } + + osip_list_add (eXosip.j_transactions, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage (message); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, NULL, NULL, NULL)); + osip_transaction_add_event (transaction, sipevent); + + __eXosip_wakeup (); + return 0; +} + +int +eXosip_message_build_answer (int tid, int status, osip_message_t ** answer) +{ + osip_transaction_t *tr = NULL; + int i = -1; + + if (tid > 0) + { + eXosip_transaction_find (tid, &tr); + } + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (status > 100 && status < 200) + { +#if 0 + /* TODO: not implemented */ + i = _eXosip_build_response_default (response, NULL, code, tr->orig_request); +#endif + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: status code 1xx for message not implemented (use 200<status<699)\n")); + return -1; + } else if (status > 199 && status < 300) + { + i = _eXosip_build_response_default (answer, NULL, status, tr->orig_request); + } else if (status > 300 && status < 699) + { + i = _eXosip_build_response_default (answer, NULL, status, tr->orig_request); + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (200<status<699)\n")); + return -1; + } + if (i != 0) + return -1; + return 0; +} + +int +eXosip_message_send_answer (int tid, int status, osip_message_t * answer) +{ + osip_transaction_t *tr = NULL; + osip_event_t *evt_answer; + int i = -1; + + if (tid > 0) + { + eXosip_transaction_find (tid, &tr); + } + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No MESSAGE transaction found\n")); + osip_message_free (answer); + return -1; + } + + /* is the transaction already answered? */ + if (tr->state == NIST_COMPLETED || tr->state == NIST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + osip_message_free (answer); + return -1; + } + + if (answer == NULL) + { + if (status > 100 && status < 200) + { +#if 0 + /* TODO: not implemented */ + i = + _eXosip_build_response_default (response, NULL, code, + tr->orig_request); +#endif + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: status code 1xx for message not implemented (use 200<status<699)\n")); + return -1; + } else if (status > 199 && status < 300) + { + i = + _eXosip_build_response_default (&answer, NULL, status, + tr->orig_request); + } else if (status > 300 && status < 699) + { + i = + _eXosip_build_response_default (&answer, NULL, status, + tr->orig_request); + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (200<status<699)\n")); + return -1; + } + if (i != 0) + return -1; + } + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/eXoptions_api.c b/exosip2/eXoptions_api.c new file mode 100644 index 0000000000000000000000000000000000000000..e8c1ec6406985e6aa6745085bc7cb0ba728c05f6 --- /dev/null +++ b/exosip2/eXoptions_api.c @@ -0,0 +1,200 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +int +eXosip_options_build_request (osip_message_t ** options, const char *to, + const char *from, const char *route) +{ + int i; + + *options = NULL; + if (to != NULL && *to == '\0') + return -1; + if (from != NULL && *from == '\0') + return -1; + if (route != NULL && *route == '\0') + route = NULL; + + i = generating_request_out_of_dialog (options, "OPTIONS", to, "UDP", from, + route); + if (i != 0) + return -1; + + /* after this delay, we should send a CANCEL */ + osip_message_set_expires (*options, "120"); + + /* osip_message_set_organization(*invite, "Jack's Org"); */ + return 0; +} + +int +eXosip_options_send_request (osip_message_t * options) +{ + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, options); + if (i != 0) + { + osip_message_free (options); + return -1; + } + + osip_list_add (eXosip.j_transactions, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage (options); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, NULL, NULL, NULL)); + osip_transaction_add_event (transaction, sipevent); + + __eXosip_wakeup (); + return 0; +} + +int +eXosip_options_build_answer (int tid, int status, osip_message_t ** answer) +{ + osip_transaction_t *tr = NULL; + int i = -1; + + *answer = NULL; + if (tid > 0) + { + eXosip_transaction_find (tid, &tr); + } + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return -1; + } + if (status > 100 && status < 200) + { +#if 0 + /* TODO: not implemented */ + i = _eXosip_build_response_default (response, NULL, code, tr->orig_request); +#endif + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: status code 1xx for options not implemented (use 200<status<699)\n")); + return -1; + } else if (status > 199 && status < 300) + { + i = _eXosip_build_response_default (answer, NULL, status, tr->orig_request); + } else if (status > 300 && status < 699) + { + i = _eXosip_build_response_default (answer, NULL, status, tr->orig_request); + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (200<status<699)\n")); + return -1; + } + if (i != 0) + return -1; + return 0; +} + +int +eXosip_options_send_answer (int tid, int status, osip_message_t * answer) +{ + osip_transaction_t *tr = NULL; + osip_event_t *evt_answer; + int i = -1; + + if (tid > 0) + { + eXosip_transaction_find (tid, &tr); + } + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No OPTIONS transaction found\n")); + osip_message_free (answer); + return -1; + } + + /* is the transaction already answered? */ + if (tr->state == NIST_COMPLETED || tr->state == NIST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + osip_message_free (answer); + return -1; + } + + if (answer == NULL) + { + if (status > 100 && status < 200) + { +#if 0 + /* TODO: not implemented */ + i = + _eXosip_build_response_default (response, NULL, code, + tr->orig_request); +#endif + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: status code 1xx for options not implemented (use 200<status<699)\n")); + return -1; + } else if (status > 199 && status < 300) + { + i = + _eXosip_build_response_default (&answer, NULL, status, + tr->orig_request); + } else if (status > 300 && status < 699) + { + i = + _eXosip_build_response_default (&answer, NULL, status, + tr->orig_request); + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: wrong status code (200<status<699)\n")); + return -1; + } + if (i != 0) + return -1; + } + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/eXosip.c b/exosip2/eXosip.c new file mode 100644 index 0000000000000000000000000000000000000000..c93f3cf3a59976f24f184d8387875b522bd15b87 --- /dev/null +++ b/exosip2/eXosip.c @@ -0,0 +1,760 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" +#include <eXosip2/eXosip.h> + + + +#ifndef WIN32 +#include <memory.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <unistd.h> +#endif + +/* Private functions */ +static jauthinfo_t *eXosip_find_authentication_info (const char *username, + const char *realm); + +eXosip_t eXosip; + +void +__eXosip_wakeup (void) +{ + jpipe_write (eXosip.j_socketctl, "w", 1); +} + +void +__eXosip_wakeup_event (void) +{ + jpipe_write (eXosip.j_socketctl_event, "w", 1); +} + + +int +eXosip_lock (void) +{ + return osip_mutex_lock ((struct osip_mutex *) eXosip.j_mutexlock); +} + +int +eXosip_unlock (void) +{ + return osip_mutex_unlock ((struct osip_mutex *) eXosip.j_mutexlock); +} + +int +eXosip_transaction_find (int tid, osip_transaction_t ** transaction) +{ + int pos = 0; + + *transaction = NULL; + while (!osip_list_eol (eXosip.j_transactions, pos)) + { + osip_transaction_t *tr; + + tr = (osip_transaction_t *) osip_list_get (eXosip.j_transactions, pos); + if (tr->transactionid == tid) + { + *transaction = tr; + return 0; + } + pos++; + } + return -1; +} + +void +eXosip_automatic_action (void) +{ + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_dialog_t *jd; + eXosip_notify_t *jn; + + eXosip_reg_t *jr; + int now; + + now = time (NULL); + + for (jc = eXosip.j_calls; jc != NULL; jc = jc->next) + { + if (jc->c_id < 1) + { + } else if (jc->c_dialogs == NULL || jc->c_dialogs->d_dialog == NULL) + { + /* an EARLY dialog may have failed with 401,407 or 3Xx */ + + osip_transaction_t *out_tr = NULL; + + out_tr = jc->c_out_tr; + + if (out_tr != NULL + && (out_tr->state == ICT_TERMINATED + || out_tr->state == NICT_TERMINATED + || out_tr->state == ICT_COMPLETED + || out_tr->state == NICT_COMPLETED) && + now - out_tr->birth_time < 120 && + out_tr->orig_request != NULL && + out_tr->last_response != NULL && + (out_tr->last_response->status_code == 401 + || out_tr->last_response->status_code == 407)) + { + /* retry with credential */ + if (jc->c_retry < 3) + { + int i; + + i = _eXosip_call_send_request_with_credential (jc, NULL, out_tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for authentication\n")); + } + jc->c_retry++; + } + } else if (out_tr != NULL + && (out_tr->state == ICT_TERMINATED + || out_tr->state == NICT_TERMINATED + || out_tr->state == ICT_COMPLETED + || out_tr->state == NICT_COMPLETED) && + now - out_tr->birth_time < 120 && + out_tr->orig_request != NULL && + out_tr->last_response != NULL && + (out_tr->last_response->status_code >= 300 + && out_tr->last_response->status_code <= 399)) + { + /* retry with credential */ + int i; + + i = _eXosip_call_redirect_request (jc, NULL, out_tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for redirection\n")); + } + } + } + + for (jd = jc->c_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog == NULL) /* finished call */ + { + } else + { + osip_transaction_t *out_tr = NULL; + + out_tr = osip_list_get (jd->d_out_trs, 0); + if (out_tr == NULL) + out_tr = jc->c_out_tr; + + if (out_tr != NULL + && (out_tr->state == ICT_TERMINATED + || out_tr->state == NICT_TERMINATED + || out_tr->state == ICT_COMPLETED + || out_tr->state == NICT_COMPLETED) && + now - out_tr->birth_time < 120 && + out_tr->orig_request != NULL && + out_tr->last_response != NULL && + (out_tr->last_response->status_code == 401 + || out_tr->last_response->status_code == 407)) + { + /* retry with credential */ + if (jd->d_retry < 3) + { + int i; + + i = + _eXosip_call_send_request_with_credential (jc, jd, out_tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for authentication\n")); + } + jd->d_retry++; + } + } else if (out_tr != NULL + && (out_tr->state == ICT_TERMINATED + || out_tr->state == NICT_TERMINATED + || out_tr->state == ICT_COMPLETED + || out_tr->state == NICT_COMPLETED) && + now - out_tr->birth_time < 120 && + out_tr->orig_request != NULL && + out_tr->last_response != NULL && + (out_tr->last_response->status_code >= 300 + && out_tr->last_response->status_code <= 399)) + { + /* retry with credential */ + int i; + + i = _eXosip_call_redirect_request (jc, jd, out_tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for redirection\n")); + } + } + } + } + } + + for (js = eXosip.j_subscribes; js != NULL; js = js->next) + { + if (js->s_id < 1) + { + } else if (js->s_dialogs == NULL) + { + osip_transaction_t *out_tr = NULL; + + out_tr = js->s_out_tr; + + if (out_tr != NULL + && (out_tr->state == NICT_TERMINATED + || out_tr->state == NICT_COMPLETED) && + now - out_tr->birth_time < 120 && + out_tr->orig_request != NULL && + out_tr->last_response != NULL && + (out_tr->last_response->status_code == 401 + || out_tr->last_response->status_code == 407)) + { + /* retry with credential */ + if (js->s_retry < 3) + { + int i; + + i = + _eXosip_subscribe_send_request_with_credential (js, NULL, + out_tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for authentication\n")); + } + js->s_retry++; + } + } + } + + for (jd = js->s_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog != NULL) /* finished call */ + { + if (jd->d_id >= 1) + { + osip_transaction_t *out_tr = NULL; + + out_tr = osip_list_get (jd->d_out_trs, 0); + if (out_tr == NULL) + out_tr = js->s_out_tr; + + if (out_tr != NULL + && (out_tr->state == NICT_TERMINATED + || out_tr->state == NICT_COMPLETED) && + now - out_tr->birth_time < 120 && + out_tr->orig_request != NULL && + out_tr->last_response != NULL && + (out_tr->last_response->status_code == 401 + || out_tr->last_response->status_code == 407)) + { + /* retry with credential */ + if (jd->d_retry < 3) + { + int i; + + i = + _eXosip_subscribe_send_request_with_credential + (js, jd, out_tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, + NULL, + "eXosip: could not clone suscbribe for authentication\n")); + } + jd->d_retry++; + } + } else if (js->s_reg_period == 0 || out_tr == NULL) + { + } else if (now - out_tr->birth_time > js->s_reg_period - 60) + { /* will expires in 60 sec: send refresh! */ + int i; + + i = + _eXosip_subscribe_send_request_with_credential (js, + jd, + out_tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone subscribe for refresh\n")); + } + } + } + } + } + } + + + for (jn = eXosip.j_notifies; jn != NULL; jn = jn->next) + { + for (jd = jn->n_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog != NULL) /* finished call */ + { + if (jd->d_id >= 1) + { + osip_transaction_t *out_tr = NULL; + + out_tr = osip_list_get (jd->d_out_trs, 0); + + if (out_tr != NULL + && (out_tr->state == NICT_TERMINATED + || out_tr->state == NICT_COMPLETED) && + now - out_tr->birth_time < 120 && + out_tr->orig_request != NULL && + out_tr->last_response != NULL && + (out_tr->last_response->status_code == 401 + || out_tr->last_response->status_code == 407)) + { + /* retry with credential */ + if (jd->d_retry < 3) + { + int i; + + i = + _eXosip_insubscription_send_request_with_credential + (jn, jd, out_tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, + NULL, + "eXosip: could not clone notify for authentication\n")); + } + jd->d_retry++; + } + } + } + } + } + } + + + for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) + { + if (jr->r_id >= 1 && jr->r_last_tr != NULL) + { + if (jr->r_reg_period == 0) + { + /* skip refresh! */ + } else if (now - jr->r_last_tr->birth_time > 900) + { + /* automatic refresh */ + eXosip_register_send_register (jr->r_id, NULL); + } else if (now - jr->r_last_tr->birth_time > jr->r_reg_period - 60) + { + /* automatic refresh */ + eXosip_register_send_register (jr->r_id, NULL); + } else if (now - jr->r_last_tr->birth_time > 120 && + (jr->r_last_tr->last_response == NULL + || (!MSG_IS_STATUS_2XX (jr->r_last_tr->last_response)))) + { + /* automatic refresh */ + eXosip_register_send_register (jr->r_id, NULL); + } else if (now - jr->r_last_tr->birth_time < 120 && + jr->r_last_tr->orig_request != NULL && + (jr->r_last_tr->last_response != NULL + && (jr->r_last_tr->last_response->status_code == 401 + || jr->r_last_tr->last_response->status_code == 407))) + { + if (jr->r_retry < 3) + { + /* TODO: improve support for several retries when + several credentials are needed */ + eXosip_register_send_register (jr->r_id, NULL); + jr->r_retry++; + } + } + } + } +} + +void +eXosip_update () +{ + static int static_id = 1; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + eXosip_dialog_t *jd; + int now; + + if (static_id > 100000) + static_id = 1; /* loop */ + + now = time (NULL); + for (jc = eXosip.j_calls; jc != NULL; jc = jc->next) + { + if (jc->c_id < 1) + { + jc->c_id = static_id; + static_id++; + } + for (jd = jc->c_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog != NULL) /* finished call */ + { + if (jd->d_id < 1) + { + jd->d_id = static_id; + static_id++; + } + } else + jd->d_id = -1; + } + } + + for (js = eXosip.j_subscribes; js != NULL; js = js->next) + { + if (js->s_id < 1) + { + js->s_id = static_id; + static_id++; + } + for (jd = js->s_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog != NULL) /* finished call */ + { + if (jd->d_id < 1) + { + jd->d_id = static_id; + static_id++; + } + } else + jd->d_id = -1; + } + } + + for (jn = eXosip.j_notifies; jn != NULL; jn = jn->next) + { + if (jn->n_id < 1) + { + jn->n_id = static_id; + static_id++; + } + for (jd = jn->n_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog != NULL) /* finished call */ + { + if (jd->d_id < 1) + { + jd->d_id = static_id; + static_id++; + } + } else + jd->d_id = -1; + } + } +} + +static jauthinfo_t * +eXosip_find_authentication_info (const char *username, const char *realm) +{ + jauthinfo_t *fallback = NULL; + jauthinfo_t *authinfo; + + for (authinfo = eXosip.authinfos; authinfo != NULL; authinfo = authinfo->next) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "INFO: authinfo: %s %s\n", realm, authinfo->realm)); + if (0 == strcmp (authinfo->username, username)) + { + if (authinfo->realm == NULL || authinfo->realm[0] == '\0') + { + fallback = authinfo; + } else if (strcmp (realm, authinfo->realm) == 0 + || 0 == strncmp (realm + 1, authinfo->realm, + strlen (realm) - 2)) + { + return authinfo; + } + } + } + + /* no matching username has been found for this realm, + try with another username... */ + for (authinfo = eXosip.authinfos; authinfo != NULL; authinfo = authinfo->next) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "INFO: authinfo: %s %s\n", realm, authinfo->realm)); + if (authinfo->realm == NULL || authinfo->realm[0] == '\0') + { + fallback = authinfo; + } else if (strcmp (realm, authinfo->realm) == 0 + || 0 == strncmp (realm + 1, authinfo->realm, strlen (realm) - 2)) + { + return authinfo; + } + } + + return fallback; +} + + +int +eXosip_clear_authentication_info () +{ + jauthinfo_t *jauthinfo; + + for (jauthinfo = eXosip.authinfos; jauthinfo != NULL; + jauthinfo = eXosip.authinfos) + { + REMOVE_ELEMENT (eXosip.authinfos, jauthinfo); + osip_free (jauthinfo); + } + return 0; +} + +int +eXosip_add_authentication_info (const char *username, const char *userid, + const char *passwd, const char *ha1, + const char *realm) +{ + jauthinfo_t *authinfos; + + if (username == NULL || username[0] == '\0') + return -1; + if (userid == NULL || userid[0] == '\0') + return -1; + + if (passwd != NULL && passwd[0] != '\0') + { + } else if (ha1 != NULL && ha1[0] != '\0') + { + } else + return -1; + + authinfos = (jauthinfo_t *) osip_malloc (sizeof (jauthinfo_t)); + if (authinfos == NULL) + return -1; + memset (authinfos, 0, sizeof (jauthinfo_t)); + + snprintf (authinfos->username, 50, "%s", username); + snprintf (authinfos->userid, 50, "%s", userid); + if (passwd != NULL && passwd[0] != '\0') + snprintf (authinfos->passwd, 50, "%s", passwd); + else if (ha1 != NULL && ha1[0] != '\0') + snprintf (authinfos->ha1, 50, "%s", ha1); + if (realm != NULL && realm[0] != '\0') + snprintf (authinfos->realm, 50, "%s", realm); + + ADD_ELEMENT (eXosip.authinfos, authinfos); + return 0; +} + +int +eXosip_add_authentication_information (osip_message_t * req, + osip_message_t * last_response) +{ + osip_authorization_t *aut = NULL; + osip_www_authenticate_t *wwwauth = NULL; + osip_proxy_authorization_t *proxy_aut = NULL; + osip_proxy_authenticate_t *proxyauth = NULL; + jauthinfo_t *authinfo = NULL; + int pos; + int i; + + if (req == NULL + || req->from == NULL + || req->from->url == NULL || req->from->url->username == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "authinfo: Invalid message\n")); + return -1; + } + + pos = 0; + osip_message_get_www_authenticate (last_response, pos, &wwwauth); + osip_message_get_proxy_authenticate (last_response, pos, &proxyauth); + if (wwwauth == NULL && proxyauth == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "authinfo: No WWW-Authenticate or Proxy-Authenticate\n")); + return -1; + } + + while (wwwauth != NULL) + { + char *uri; + + authinfo = eXosip_find_authentication_info (req->from->url->username, + wwwauth->realm); + if (authinfo == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "authinfo: No authentication found for %s %s\n", + req->from->url->username, wwwauth->realm)); + return -1; + } + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "authinfo: %s\n", authinfo->username)); + i = osip_uri_to_str (req->req_uri, &uri); + if (i != 0) + return -1; + + i = __eXosip_create_authorization_header (last_response, uri, + authinfo->userid, + authinfo->passwd, + authinfo->ha1, &aut, + req->sip_method); + osip_free (uri); + if (i != 0) + return -1; + + if (aut != NULL) + { + osip_list_add (req->authorizations, aut, -1); + osip_message_force_update (req); + } + + pos++; + osip_message_get_www_authenticate (last_response, pos, &wwwauth); + } + + pos = 0; + while (proxyauth != NULL) + { + char *uri; + + authinfo = eXosip_find_authentication_info (req->from->url->username, + proxyauth->realm); + if (authinfo == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "authinfo: No authentication found for %s %s\n", + req->from->url->username, proxyauth->realm)); + return -1; + } + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "authinfo: %s\n", authinfo->username)); + i = osip_uri_to_str (req->req_uri, &uri); + if (i != 0) + return -1; + + i = __eXosip_create_proxy_authorization_header (last_response, uri, + authinfo->userid, + authinfo->passwd, + authinfo->ha1, + &proxy_aut, + req->sip_method); + osip_free (uri); + if (i != 0) + return -1; + + if (proxy_aut != NULL) + { + osip_list_add (req->proxy_authorizations, proxy_aut, -1); + osip_message_force_update (req); + } + + pos++; + osip_message_get_proxy_authenticate (last_response, pos, &proxyauth); + } + + return 0; +} + +int +eXosip_update_top_via (osip_message_t * sip) +{ + char locip[50]; + char *tmp = (char *) osip_malloc (256 * sizeof (char)); + osip_via_t *via = (osip_via_t *) osip_list_get (sip->vias, 0); + int i; + + i = _eXosip_find_protocol(sip); + + osip_list_remove (sip->vias, 0); + osip_via_free (via); +#ifdef SM + eXosip_get_localip_for (sip->req_uri->host, locip, 49); +#else + if (i==IPPROTO_UDP) + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, 49); + else if (i==IPPROTO_TCP) + eXosip_guess_ip_for_via (eXosip.net_interfaces[1].net_ip_family, locip, 49); + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol (using default UDP)\n")); + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, 49); + } +#endif + if (i==IPPROTO_UDP) + { + if (eXosip.net_interfaces[0].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/UDP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, + via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/UDP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, + via_branch_new_random ()); + } + else if (i==IPPROTO_TCP) + { + if (eXosip.net_interfaces[1].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/TCP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, + via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/TCP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, + via_branch_new_random ()); + } + + osip_via_init (&via); + osip_via_parse (via, tmp); + osip_list_add (sip->vias, via, 0); + osip_free (tmp); + + return 0; +} diff --git a/exosip2/eXosip2.h b/exosip2/eXosip2.h new file mode 100644 index 0000000000000000000000000000000000000000..0ef78c5842065259560c6a7112e27a35c74af0e1 --- /dev/null +++ b/exosip2/eXosip2.h @@ -0,0 +1,533 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EXOSIP2_H__ +#define __EXOSIP2_H__ + +#ifdef WIN32 +#include <stdio.h> +#include <stdlib.h> +#include <winsock2.h> +#include <ws2tcpip.h> +#define snprintf _snprintf +#define close(s) closesocket(s) +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#endif + +#include <stdio.h> + +#include <osip2/osip.h> +#include <osip2/osip_dialog.h> + +#include <eXosip2/eXosip.h> + +#include "jpipe.h" + +#ifndef JD_EMPTY + +#define JD_EMPTY 0 +#define JD_INITIALIZED 1 +#define JD_TRYING 2 +#define JD_QUEUED 3 +#define JD_RINGING 4 +#define JD_ESTABLISHED 5 +#define JD_REDIRECTED 6 +#define JD_AUTH_REQUIRED 7 +#define JD_CLIENTERROR 8 +#define JD_SERVERERROR 9 +#define JD_GLOBALFAILURE 10 +#define JD_TERMINATED 11 + +#define JD_MAX 11 + +#endif + +#define EXOSIP_VERSION "0.1" + +#ifdef __cplusplus +extern "C" +{ +#endif + + void eXosip_update (void); + void __eXosip_wakeup (void); + + struct __eXosip_sockaddr + { + u_char ss_len; + u_char ss_family; + u_char padding[128 - 2]; + }; + + typedef struct eXosip_dialog_t eXosip_dialog_t; + + struct eXosip_dialog_t + { + + int d_id; + int d_STATE; + osip_dialog_t *d_dialog; /* active dialog */ + + int d_timer; + osip_message_t *d_200Ok; + osip_message_t *d_ack; + + osip_list_t *d_inc_trs; + osip_list_t *d_out_trs; + int d_retry; /* avoid too many unsuccessfull retry */ + + eXosip_dialog_t *next; + eXosip_dialog_t *parent; + }; + + typedef struct eXosip_subscribe_t eXosip_subscribe_t; + + struct eXosip_subscribe_t + { + + int s_id; + int s_ss_status; + int s_ss_reason; + int s_reg_period; + eXosip_dialog_t *s_dialogs; + + int s_retry; /* avoid too many unsuccessfull retry */ + osip_transaction_t *s_inc_tr; + osip_transaction_t *s_out_tr; + + eXosip_subscribe_t *next; + eXosip_subscribe_t *parent; + }; + + typedef struct eXosip_notify_t eXosip_notify_t; + + struct eXosip_notify_t + { + + int n_id; + char n_uri[255]; + int n_online_status; + + int n_ss_status; + int n_ss_reason; + int n_ss_expires; + eXosip_dialog_t *n_dialogs; + + osip_transaction_t *n_inc_tr; + osip_transaction_t *n_out_tr; + + eXosip_notify_t *next; + eXosip_notify_t *parent; + }; + + typedef struct eXosip_call_t eXosip_call_t; + + struct eXosip_call_t + { + + int c_id; + eXosip_dialog_t *c_dialogs; + osip_transaction_t *c_inc_tr; + osip_transaction_t *c_out_tr; + int c_retry; /* avoid too many unsuccessfull retry */ + osip_transaction_t *c_inc_options_tr; + osip_transaction_t *c_out_options_tr; + void *external_reference; + + /* cache old credentials for reuse in next request */ + osip_message_t *response_auth; + + eXosip_call_t *next; + eXosip_call_t *parent; + }; + + + typedef struct eXosip_reg_t eXosip_reg_t; + + struct eXosip_reg_t + { + + int r_id; + + int r_reg_period; /* delay between registration */ + char *r_aor; /* sip identity */ + char *r_registrar; /* registrar */ + char *r_contact; /* list of contacts string */ + + osip_transaction_t *r_last_tr; + int r_retry; /* avoid too many unsuccessfull retry */ + + char transport[10]; /* transport used for registration */ + + struct __eXosip_sockaddr addr; + int len; + + eXosip_reg_t *next; + eXosip_reg_t *parent; + }; + + + typedef struct eXosip_pub_t eXosip_pub_t; + + struct eXosip_pub_t + { + int p_id; + + time_t p_expires; /* expiration date (started+period) */ + int p_period; /* delay between registration */ + char p_aor[256]; /* sip identity */ + char p_sip_etag[64]; /* sip_etag from 200ok */ + + osip_transaction_t *p_last_tr; + eXosip_pub_t *next; + eXosip_pub_t *parent; + }; + + int _eXosip_pub_update (eXosip_pub_t ** pub, osip_transaction_t * tr, + osip_message_t * answer); + int _eXosip_pub_find_by_aor (eXosip_pub_t ** pub, const char *aor); + int _eXosip_pub_init (eXosip_pub_t ** pub, const char *aor, const char *exp); + void _eXosip_pub_free (eXosip_pub_t * pub); + + typedef struct jauthinfo_t jauthinfo_t; + + struct jauthinfo_t + { + char username[50]; + char userid[50]; + char passwd[50]; + char ha1[50]; + char realm[50]; + jauthinfo_t *parent; + jauthinfo_t *next; + }; + + int + __eXosip_create_authorization_header (osip_message_t * previous_answer, + const char *rquri, + const char *username, + const char *passwd, + const char *ha1, + osip_authorization_t ** auth, + const char *method); + int __eXosip_create_proxy_authorization_header (osip_message_t * + previous_answer, + const char *rquri, + const char *username, + const char *passwd, + const char *ha1, + osip_proxy_authorization_t + ** auth, + const char *method); + + eXosip_event_t *eXosip_event_init_for_call (int type, eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_transaction_t * tr); + + eXosip_event_t *eXosip_event_init_for_subscribe (int type, + eXosip_subscribe_t * js, + eXosip_dialog_t * jd, + osip_transaction_t * tr); + eXosip_event_t *eXosip_event_init_for_notify (int type, + eXosip_notify_t * jn, + eXosip_dialog_t * jd, + osip_transaction_t * tr); + eXosip_event_t *eXosip_event_init_for_reg (int type, eXosip_reg_t * jr, + osip_transaction_t * tr); + eXosip_event_t *eXosip_event_init_for_message (int type, + osip_transaction_t * tr); + + int eXosip_event_init (eXosip_event_t ** je, int type); + void report_call_event (int evt, eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * tr); + void report_options_event (int evt, osip_transaction_t * tr); + void report_event (eXosip_event_t * je, osip_message_t * sip); + int eXosip_event_add (eXosip_event_t * je); + eXosip_event_t *eXosip_event_wait (int tv_s, int tv_ms); + eXosip_event_t *eXosip_event_get (void); + + typedef void (*eXosip_callback_t) (int type, eXosip_event_t *); + + char *strdup_printf (const char *fmt, ...); + +#define eXosip_trace(loglevel,args) do \ +{ \ + char *__strmsg; \ + __strmsg=strdup_printf args ; \ + OSIP_TRACE(osip_trace(__FILE__,__LINE__,(loglevel),NULL,"%s\n",__strmsg)); \ + osip_free (__strmsg); \ +}while (0); + +#ifndef EXOSIP_MAX_SOCKETS +#define EXOSIP_MAX_SOCKETS 200 +#endif + + /* structure used for keepalive management with connected protocols (TCP or TLS) */ + struct eXosip_socket { + int socket; + char remote_ip[50]; + int remote_port; + }; + + struct eXosip_net { + char net_firewall_ip[50]; /* ip address to use for masquerading contacts */ + int net_ip_family; /* AF_INET6 or AF_INET */ + struct sockaddr_storage ai_addr; + char net_port[20]; /* port for receiving message/connection */ + int net_socket; /* initial socket for receiving message/connection */ + int net_protocol; /* initial socket for receiving message/connection */ + struct eXosip_socket net_socket_tab[EXOSIP_MAX_SOCKETS]; + }; + + char *_eXosip_transport_protocol(osip_message_t *msg); + int _eXosip_find_protocol(osip_message_t *msg); + int _eXosip_tcp_find_socket(char *host, int port); + int _eXosip_tcp_connect_socket(char *host, int port); + int setsockopt_ipv6only (int sock); + + int _eXosip_recvfrom(int s, char *buf, int len, unsigned int flags, struct sockaddr *from, socklen_t *fromlen); + int _eXosip_sendto(int s, const void* buf, size_t len, int flags, + const struct sockaddr* to, socklen_t tolen); + + typedef struct eXosip_t eXosip_t; + + struct eXosip_t + { + int forced_localip; /* set to 1 for masquerading contact headers */ + struct eXosip_net net_interfaces[3]; + char *user_agent; + + eXosip_call_t *j_calls; /* my calls */ + eXosip_subscribe_t *j_subscribes; /* my friends */ + eXosip_notify_t *j_notifies; /* my susbscribers */ + osip_list_t *j_transactions; + + eXosip_reg_t *j_reg; /* my registrations */ + eXosip_pub_t *j_pub; /* my publications */ + + void *j_cond; + void *j_mutexlock; + + osip_t *j_osip; + int j_stop_ua; + void *j_thread; + jpipe_t *j_socketctl; + jpipe_t *j_socketctl_event; + + osip_fifo_t *j_events; + + jauthinfo_t *authinfos; + + int keep_alive; + int learn_port; + int http_port; + char http_proxy[256]; + char http_outbound_proxy[256]; + }; + + typedef struct jinfo_t jinfo_t; + + struct jinfo_t + { + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + }; + + int eXosip_guess_ip_for_via (int family, char *address, int size); + +/** + * Prepare addrinfo for socket binding and resolv hostname + * + * @param addrinfo informations about the connections + * @param hostname hostname to resolv. + * @param service port number or "sip" SRV record if service=0 + */ + int eXosip_get_addrinfo (struct addrinfo **addrinfo, const char *hostname, + int service, int protocol); + + int eXosip_set_callbacks (osip_t * osip); + int cb_snd_message (osip_transaction_t * tr, osip_message_t * sip, + char *host, int port, int out_socket); + int cb_udp_snd_message (osip_transaction_t * tr, osip_message_t * sip, + char *host, int port, int out_socket); + int cb_tcp_snd_message (osip_transaction_t * tr, osip_message_t * sip, + char *host, int port, int out_socket); + char *osip_call_id_new_random (void); + char *osip_to_tag_new_random (void); + char *osip_from_tag_new_random (void); + unsigned int via_branch_new_random (void); + void __eXosip_delete_jinfo (osip_transaction_t * transaction); + jinfo_t *__eXosip_new_jinfo (eXosip_call_t * jc, eXosip_dialog_t * jd, + eXosip_subscribe_t * js, eXosip_notify_t * jn); + + int eXosip_dialog_init_as_uac (eXosip_dialog_t ** jd, osip_message_t * _200Ok); + int eXosip_dialog_init_as_uas (eXosip_dialog_t ** jd, + osip_message_t * _invite, + osip_message_t * _200Ok); + void eXosip_dialog_free (eXosip_dialog_t * jd); + void eXosip_dialog_set_state (eXosip_dialog_t * jd, int state); + void eXosip_delete_early_dialog (eXosip_dialog_t * jd); + + + int isrfc1918 (char *ipaddr); + void eXosip_get_localip_from_via (osip_message_t *, char *localip, int size); + int generating_request_out_of_dialog (osip_message_t ** dest, + const char *method, const char *to, + const char *transport, + const char *from, const char *proxy); + int generating_publish (osip_message_t ** message, const char *to, + const char *from, const char *route); + int generating_cancel (osip_message_t ** dest, + osip_message_t * request_cancelled); + int generating_bye (osip_message_t ** bye, osip_dialog_t * dialog, char *transport); + int generating_ack_for_2xx (osip_message_t ** ack, osip_dialog_t * dialog); + + int eXosip_update_top_via (osip_message_t * sip); + int eXosip_add_authentication_information (osip_message_t * req, + osip_message_t * last_response); + int _eXosip_reg_find (eXosip_reg_t ** reg, osip_transaction_t * tr); + int eXosip_reg_init (eXosip_reg_t ** jr, const char *from, + const char *proxy, const char *contact); + void eXosip_reg_free (eXosip_reg_t * jreg); + int generating_register (osip_message_t ** reg, char *transport, char *from, + char *proxy, char *contact, int expires); + + int _eXosip_call_redirect_request (eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_transaction_t * out_tr); + int _eXosip_call_send_request_with_credential (eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_transaction_t * out_tr); + int eXosip_transaction_find (int tid, osip_transaction_t ** transaction); + int eXosip_call_dialog_find (int jid, eXosip_call_t ** jc, + eXosip_dialog_t ** jd); + int eXosip_notify_dialog_find (int nid, eXosip_notify_t ** jn, + eXosip_dialog_t ** jd); + int eXosip_subscribe_dialog_find (int nid, eXosip_subscribe_t ** js, + eXosip_dialog_t ** jd); + int eXosip_call_find (int cid, eXosip_call_t ** jc); + int eXosip_dialog_set_200ok (eXosip_dialog_t * _jd, osip_message_t * _200Ok); + + int _eXosip_answer_invite_3456xx (eXosip_call_t * jc, eXosip_dialog_t * jd, + int code, osip_message_t ** answer); + int _eXosip_answer_invite_2xx (eXosip_call_t * jc, eXosip_dialog_t * jd, + int code, osip_message_t ** answer); + int _eXosip_answer_invite_1xx (eXosip_call_t * jc, eXosip_dialog_t * jd, + int code, osip_message_t ** answer); + int _eXosip_default_answer_invite_1xx (eXosip_call_t * jc, + eXosip_dialog_t * jd, int code); + int _eXosip_default_answer_invite_3456xx (eXosip_call_t * jc, + eXosip_dialog_t * jd, int code); + int _eXosip_insubscription_answer_1xx (eXosip_notify_t * jc, + eXosip_dialog_t * jd, int code); + int _eXosip_insubscription_answer_2xx (eXosip_notify_t * jn, + eXosip_dialog_t * jd, int code); + int _eXosip_insubscription_answer_3456xx (eXosip_notify_t * jn, + eXosip_dialog_t * jd, int code); + + int eXosip_build_response_default (int jid, int status); + int _eXosip_build_response_default (osip_message_t ** dest, + osip_dialog_t * dialog, int status, + osip_message_t * request); + int complete_answer_that_establish_a_dialog (osip_message_t * response, + osip_message_t * request); + int _eXosip_build_request_within_dialog (osip_message_t ** dest, + const char *method, + osip_dialog_t * dialog, + const char *transport); + void eXosip_kill_transaction (osip_list_t * transactions); + int eXosip_remove_transaction_from_call (osip_transaction_t * tr, + eXosip_call_t * jc); + osip_transaction_t *eXosip_find_last_inc_notify (eXosip_subscribe_t * jn, + eXosip_dialog_t * jd); + osip_transaction_t *eXosip_find_last_out_notify (eXosip_notify_t * jn, + eXosip_dialog_t * jd); + osip_transaction_t *eXosip_find_last_inc_subscribe (eXosip_notify_t * jn, + eXosip_dialog_t * jd); + osip_transaction_t *eXosip_find_last_out_subscribe (eXosip_subscribe_t * js, + eXosip_dialog_t * jd); + + osip_transaction_t *eXosip_find_last_transaction (eXosip_call_t * jc, + eXosip_dialog_t * jd, + const char *method); + osip_transaction_t *eXosip_find_last_inc_transaction (eXosip_call_t * jc, + eXosip_dialog_t * jd, + const char *method); + osip_transaction_t *eXosip_find_last_out_transaction (eXosip_call_t * jc, + eXosip_dialog_t * jd, + const char *method); + osip_transaction_t *eXosip_find_last_invite (eXosip_call_t * jc, + eXosip_dialog_t * jd); + osip_transaction_t *eXosip_find_last_inc_invite (eXosip_call_t * jc, + eXosip_dialog_t * jd); + osip_transaction_t *eXosip_find_last_out_invite (eXosip_call_t * jc, + eXosip_dialog_t * jd); + + + int eXosip_call_init (eXosip_call_t ** jc); + void eXosip_call_free (eXosip_call_t * jc); + void __eXosip_call_remove_dialog_reference_in_call (eXosip_call_t * jc, + eXosip_dialog_t * jd); + int eXosip_read_message (int max_message_nb, int sec_max, int usec_max); + void eXosip_release_terminated_calls (void); + void eXosip_release_terminated_registrations (void); + + + int eXosip_subscribe_init (eXosip_subscribe_t ** js); + void eXosip_subscribe_free (eXosip_subscribe_t * js); + int _eXosip_subscribe_set_refresh_interval (eXosip_subscribe_t * js, + osip_message_t * inc_subscribe); + int eXosip_subscribe_need_refresh (eXosip_subscribe_t * js, + eXosip_dialog_t * jd, int now); + int _eXosip_subscribe_send_request_with_credential (eXosip_subscribe_t * js, + eXosip_dialog_t * jd, + osip_transaction_t * out_tr); + int eXosip_notify_init (eXosip_notify_t ** jn, osip_message_t * inc_subscribe); + void eXosip_notify_free (eXosip_notify_t * jn); + int _eXosip_notify_set_contact_info (eXosip_notify_t * jn, char *uri); + int _eXosip_notify_set_refresh_interval (eXosip_notify_t * jn, + osip_message_t * inc_subscribe); + void _eXosip_notify_add_expires_in_2XX_for_subscribe (eXosip_notify_t * jn, + osip_message_t * answer); + int _eXosip_insubscription_send_request_with_credential (eXosip_notify_t * + jn, + eXosip_dialog_t * + jd, + osip_transaction_t + * out_tr); + + int eXosip_is_public_address (const char *addr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/exosip2/eXpublish_api.c b/exosip2/eXpublish_api.c new file mode 100644 index 0000000000000000000000000000000000000000..36a937664b4692db5e08a8a8505bf8430ba3f8ce --- /dev/null +++ b/exosip2/eXpublish_api.c @@ -0,0 +1,168 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" +#include <eXosip2/eXosip.h> + +extern eXosip_t eXosip; + +int +eXosip_build_publish (osip_message_t ** message, + const char *to, + const char *from, + const char *route, + const char *event, + const char *expires, const char *ctype, const char *body) +{ + int i; + + *message = NULL; + + if (to == NULL || to[0] == '\0') + return -1; + if (from == NULL || from[0] == '\0') + return -1; + if (event == NULL || event[0] == '\0') + return -1; + if (ctype == NULL || ctype[0] == '\0') + { + if (body != NULL && body[0] != '\0') + return -1; + } else + { + if (body == NULL || body[0] == '\0') + return -1; + } + + i = generating_publish (message, to, from, route); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot send message (cannot build PUBLISH)! ")); + return -1; + } + + if (body != NULL && body[0] != '\0' && ctype != NULL && ctype[0] != '\0') + { + osip_message_set_content_type (*message, ctype); + osip_message_set_body (*message, body, strlen (body)); + osip_message_set_header (*message, "Content-Disposition", + "render;handling=required"); + } + if (expires != NULL && expires[0] != '\0') + osip_message_set_expires (*message, expires); + else + osip_message_set_expires (*message, "3600"); + + osip_message_set_header (*message, "Event", event); + return 0; +} + +int +eXosip_publish (osip_message_t * message, const char *to) +{ + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + eXosip_pub_t *pub = NULL; + + if (message == NULL) + return -1; + if (message->cseq == NULL || message->cseq->number == NULL) + { + osip_message_free (message); + return -1; + } + if (to == NULL) + { + osip_message_free (message); + return -1; + } + + i = _eXosip_pub_find_by_aor (&pub, to); + if (i != 0 || pub == NULL) + { + osip_header_t *expires; + + osip_message_get_expires (message, 0, &expires); + if (expires == NULL || expires->hvalue == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: missing expires header in PUBLISH!")); + osip_message_free (message); + return -1; + } else + { + /* start a new publication context */ + _eXosip_pub_init (&pub, to, expires->hvalue); + if (pub == NULL) + { + osip_message_free (message); + return -1; + } + ADD_ELEMENT (eXosip.j_pub, pub); + } + } else + { + if (pub->p_sip_etag != NULL && pub->p_sip_etag[0] != '\0') + { + /* increase cseq */ + osip_message_set_header (message, "SIP-If-Match", pub->p_sip_etag); + } + + if (pub->p_last_tr != NULL && pub->p_last_tr->cseq != NULL + && pub->p_last_tr->cseq->number != NULL) + { + int osip_cseq_num = osip_atoi (pub->p_last_tr->cseq->number); + int length = strlen (pub->p_last_tr->cseq->number); + + osip_cseq_num++; + osip_free (message->cseq->number); + message->cseq->number = (char *) osip_malloc (length + 2); /* +2 like for 9 to 10 */ + sprintf (message->cseq->number, "%i", osip_cseq_num); + } + } + + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, message); + if (i != 0) + { + osip_message_free (message); + return -1; + } + + if (pub->p_last_tr != NULL) + osip_list_add (eXosip.j_transactions, pub->p_last_tr, 0); + pub->p_last_tr = transaction; + + sipevent = osip_new_outgoing_sipmessage (message); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, NULL, NULL, NULL)); + osip_transaction_add_event (transaction, sipevent); + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/eXrefer_api.c b/exosip2/eXrefer_api.c new file mode 100644 index 0000000000000000000000000000000000000000..9b6a2ec5a6c9fa1965c8d1bc7672db96c8c1d4e3 --- /dev/null +++ b/exosip2/eXrefer_api.c @@ -0,0 +1,74 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" +#include <eXosip2/eXosip.h> + +extern eXosip_t eXosip; + +int +eXosip_refer_build_request (osip_message_t ** refer, const char *refer_to, + const char *from, const char *to, const char *proxy) +{ + int i; + + *refer = NULL; + i = generating_request_out_of_dialog (refer, "REFER", to, "UDP", from, proxy); + if (i != 0) + { + return -1; + } + + osip_message_set_header (*refer, "Refer-to", refer_to); + return 0; +} + +int +eXosip_refer_send_request (osip_message_t * refer) +{ + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + if (refer == NULL) + return -1; + + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, refer); + if (i != 0) + { + osip_message_free (refer); + return -1; + } + + osip_list_add (eXosip.j_transactions, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage (refer); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, NULL, NULL, NULL)); + osip_transaction_add_event (transaction, sipevent); + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/eXregister_api.c b/exosip2/eXregister_api.c new file mode 100644 index 0000000000000000000000000000000000000000..23f61f240e635e20398088b2789c59a690ade776 --- /dev/null +++ b/exosip2/eXregister_api.c @@ -0,0 +1,376 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +static int _eXosip_register_build_register (eXosip_reg_t * jr, + osip_message_t ** _reg); + +static eXosip_reg_t * +eXosip_reg_find (int rid) +{ + eXosip_reg_t *jr; + + for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) + { + if (jr->r_id == rid) + { + return jr; + } + } + return NULL; +} + + +static int +_eXosip_register_build_register (eXosip_reg_t * jr, osip_message_t ** _reg) +{ + osip_message_t *reg=NULL; + struct eXosip_net *net; + int i; + + reg = NULL; + *_reg = NULL; + + if (jr->r_last_tr != NULL) + { + if (jr->r_last_tr->state != NICT_TERMINATED + && jr->r_last_tr->state != NICT_COMPLETED) + return -1; + else + { + osip_message_t *last_response=NULL; + osip_transaction_t *tr; + osip_message_clone(jr->r_last_tr->orig_request, ®); + if (reg==NULL) + return -1; + /* reg = jr->r_last_tr->orig_request; */ + if (jr->r_last_tr->last_response!=NULL) + { + osip_message_clone(jr->r_last_tr->last_response, &last_response); + if (last_response==NULL) + { + osip_message_free(reg); + return -1; + } + } + + __eXosip_delete_jinfo (jr->r_last_tr); + tr = jr->r_last_tr; + jr->r_last_tr = NULL; + osip_list_add (eXosip.j_transactions, tr, 0); + + /* modify the REGISTER request */ + { + int osip_cseq_num = osip_atoi (reg->cseq->number); + int length = strlen (reg->cseq->number); + + + osip_authorization_t *aut; + osip_proxy_authorization_t *proxy_aut; + + aut = (osip_authorization_t *) osip_list_get (reg->authorizations, 0); + while (aut != NULL) + { + osip_list_remove (reg->authorizations, 0); + osip_authorization_free (aut); + aut = + (osip_authorization_t *) osip_list_get (reg->authorizations, 0); + } + + proxy_aut = + (osip_proxy_authorization_t *) osip_list_get (reg-> + proxy_authorizations, + 0); + while (proxy_aut != NULL) + { + osip_list_remove (reg->proxy_authorizations, 0); + osip_proxy_authorization_free (proxy_aut); + proxy_aut = + (osip_proxy_authorization_t *) osip_list_get (reg-> + proxy_authorizations, + 0); + } + + if (0==osip_strcasecmp(jr->transport, "udp")) + net = &eXosip.net_interfaces[0]; + else if (0==osip_strcasecmp(jr->transport, "tcp")) + net = &eXosip.net_interfaces[1]; + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol '%s' (default to UDP)\n", + jr->transport)); + net = &eXosip.net_interfaces[0]; + } + + /* + modify the port number when masquerading is ON. + */ + if (net->net_firewall_ip[0]!='\0') + { + int pos=0; + while (!osip_list_eol(reg->contacts,pos)) + { + osip_contact_t *co; + co = (osip_contact_t *)osip_list_get(reg->contacts,pos); + pos++; + if (co!=NULL && co->url!=NULL && co->url->host!=NULL + && 0==osip_strcasecmp(co->url->host, + net->net_firewall_ip)) + { + if (co->url->port==NULL && + 0!=osip_strcasecmp(net->net_port, "5060")) + { + co->url->port=osip_strdup(net->net_port); + } + else if (co->url->port!=NULL && + 0!=osip_strcasecmp(net->net_port, co->url->port)) + { + osip_free(co->url->port); + co->url->port=osip_strdup(net->net_port); + } + } + } + } + + if (-1 == eXosip_update_top_via (reg)) + { + osip_message_free (reg); + if (last_response != NULL) + osip_message_free (last_response); + return -1; + } + + osip_cseq_num++; + osip_free (reg->cseq->number); + reg->cseq->number = (char *) osip_malloc (length + 2); /* +2 like for 9 to 10 */ + sprintf (reg->cseq->number, "%i", osip_cseq_num); + + { + osip_header_t *exp; + + osip_message_header_get_byname (reg, "expires", 0, &exp); + osip_free (exp->hvalue); + exp->hvalue = (char *) osip_malloc (10); + snprintf (exp->hvalue, 9, "%i", jr->r_reg_period); + } + + osip_message_force_update (reg); + } + + if (last_response != NULL) + { + if (MSG_IS_STATUS_4XX (last_response)) + { + eXosip_add_authentication_information (reg, last_response); + } + osip_message_free (last_response); + } + } + } + if (reg == NULL) + { + i = generating_register (®, jr->transport, + jr->r_aor, jr->r_registrar, jr->r_contact, + jr->r_reg_period); + if (i != 0) + { + return -2; + } + } + + *_reg = reg; + return 0; +} + +int +eXosip_register_build_initial_register (const char *from, const char *proxy, + const char *contact, int expires, + osip_message_t ** reg) +{ + eXosip_reg_t *jr = NULL; + int i; + + *reg = NULL; + + if (eXosip.net_interfaces[0].net_socket<=0 + && eXosip.net_interfaces[1].net_socket<=0 + && eXosip.net_interfaces[2].net_socket<=0) + return -1; + + /* Avoid adding the same registration info twice to prevent mem leaks */ + for (jr = eXosip.j_reg; jr != NULL; jr = jr->next) + { + if (strcmp (jr->r_aor, from) == 0 && strcmp (jr->r_registrar, proxy) == 0) + { + break; + } + } + if (jr == NULL) + { + /* Add new registration info */ + i = eXosip_reg_init (&jr, from, proxy, contact); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot register! ")); + return i; + } + ADD_ELEMENT (eXosip.j_reg, jr); + } + + /* Guess transport from existing connections */ + if (eXosip.net_interfaces[0].net_socket>0) + osip_strncpy(jr->transport, "UDP", sizeof(jr->transport)-1); + else if (eXosip.net_interfaces[1].net_socket>0) + osip_strncpy(jr->transport, "TCP", sizeof(jr->transport)-1); + else if (eXosip.net_interfaces[2].net_socket>0) + osip_strncpy(jr->transport, "TLS", sizeof(jr->transport)-1); + + /* build register */ + jr->r_reg_period = expires; + + i = _eXosip_register_build_register (jr, reg); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot build REGISTER!")); + *reg = NULL; + return i; + } + return jr->r_id; +} + +int +eXosip_register_build_register (int rid, int expires, osip_message_t ** reg) +{ + eXosip_reg_t *jr; + int i; + + *reg = NULL; + jr = eXosip_reg_find (rid); + if (jr == NULL) + { + /* fprintf(stderr, "eXosip: no registration info saved!\n"); */ + return -1; + } + jr->r_reg_period = expires; + if (jr->r_reg_period == 0) + { + } /* unregistration */ + else if (jr->r_reg_period > 3600) + jr->r_reg_period = 3600; + else if (jr->r_reg_period < 200) /* too low */ + jr->r_reg_period = 200; + + if (jr->r_last_tr != NULL) + { + if (jr->r_last_tr->state != NICT_TERMINATED + && jr->r_last_tr->state != NICT_COMPLETED) + { + /* fprintf(stderr, "eXosip: a registration is already pending!\n"); */ + return -1; + } + } + + i = _eXosip_register_build_register (jr, reg); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot build REGISTER!")); + *reg = NULL; + return i; + } + return 0; +} + +int +eXosip_register_send_register (int rid, osip_message_t * reg) +{ + osip_transaction_t *transaction; + osip_event_t *sipevent; + eXosip_reg_t *jr; + char *transport; + int i; + + jr = eXosip_reg_find (rid); + if (jr == NULL) + { + osip_message_free (reg); + return -1; + } + + if (jr->r_last_tr != NULL) + { + if (jr->r_last_tr->state != NICT_TERMINATED + && jr->r_last_tr->state != NICT_COMPLETED) + { + osip_message_free (reg); + return -1; + } + } + + if (reg == NULL) + { + i = _eXosip_register_build_register (jr, ®); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot build REGISTER!")); + return i; + } + } + + transport = _eXosip_transport_protocol(reg); + osip_strncpy(jr->transport, transport, sizeof(jr->transport)-1); + + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, reg); + if (i != 0) + { + /* TODO: release the j_call.. */ + + osip_message_free (reg); + return -2; + } + + jr->r_last_tr = transaction; + + /* send REGISTER */ + sipevent = osip_new_outgoing_sipmessage (reg); + sipevent->transactionid = transaction->transactionid; + osip_message_force_update (reg); + + osip_transaction_add_event (transaction, sipevent); + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/eXsubscription_api.c b/exosip2/eXsubscription_api.c new file mode 100644 index 0000000000000000000000000000000000000000..84c25f288007258335ddbe57ec4c2df5cf623761 --- /dev/null +++ b/exosip2/eXsubscription_api.c @@ -0,0 +1,372 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +int +eXosip_subscribe_build_initial_request (osip_message_t ** sub, const char *to, + const char *from, const char *route, + const char *event, int expires) +{ + char tmp[10]; + int i; + osip_uri_param_t *uri_param = NULL; + osip_to_t *_to=NULL; + + *sub = NULL; + if (to != NULL && *to == '\0') + return -1; + if (from != NULL && *from == '\0') + return -1; + if (event != NULL && *event == '\0') + return -1; + if (route != NULL && *route == '\0') + route = NULL; + + i = osip_to_init(&_to); + if (i!=0) + return -1; + + i = osip_to_parse(_to, to); + if (i!=0) + { + osip_to_free(_to); + return -1; + } + + osip_uri_uparam_get_byname(_to->url, "transport", &uri_param); + if (uri_param != NULL && uri_param->gvalue != NULL) + { + i = generating_request_out_of_dialog (sub, "SUBSCRIBE", to, "UDP", from, route); + } + else + { + if (eXosip.net_interfaces[0].net_socket>0) + i = generating_request_out_of_dialog (sub, "SUBSCRIBE", to, "UDP", from, route); + else if (eXosip.net_interfaces[1].net_socket>0) + i = generating_request_out_of_dialog (sub, "SUBSCRIBE", to, "TCP", from, route); + else + i = generating_request_out_of_dialog (sub, "SUBSCRIBE", to, "UDP", from, route); + } + + osip_to_free(_to); + if (i != 0) + return -1; + + snprintf (tmp, 10, "%i", expires); + osip_message_set_expires (*sub, tmp); + + osip_message_set_header (*sub, "Event", event); + + return 0; +} + +int +eXosip_subscribe_send_initial_request (osip_message_t * subscribe) +{ + eXosip_subscribe_t *js = NULL; + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + i = eXosip_subscribe_init (&js); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot subscribe.")); + osip_message_free (subscribe); + return -1; + } + + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, subscribe); + if (i != 0) + { + eXosip_subscribe_free (js); + osip_message_free (subscribe); + return -1; + } + + _eXosip_subscribe_set_refresh_interval (js, subscribe); + js->s_out_tr = transaction; + + sipevent = osip_new_outgoing_sipmessage (subscribe); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, NULL, js, NULL)); + osip_transaction_add_event (transaction, sipevent); + + ADD_ELEMENT (eXosip.j_subscribes, js); + eXosip_update (); /* fixed? */ + __eXosip_wakeup (); + return 0; +} + +int +eXosip_subscribe_build_refresh_request (int did, osip_message_t ** sub) +{ + eXosip_dialog_t *jd = NULL; + eXosip_subscribe_t *js = NULL; + + osip_transaction_t *transaction; + char *transport; + int i; + + *sub = NULL; + if (did > 0) + { + eXosip_subscribe_dialog_find (did, &js, &jd); + } + if (jd == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No subscribe here?\n")); + return -1; + } + + transaction = NULL; + transaction = eXosip_find_last_out_subscribe (js, jd); + + if (transaction != NULL) + { + if (transaction->state != NICT_TERMINATED && + transaction->state != NIST_TERMINATED && + transaction->state != NICT_COMPLETED && + transaction->state != NIST_COMPLETED) + return -1; + } + + transport = NULL; + if (transaction!=NULL && transaction->orig_request!=NULL) + transport = _eXosip_transport_protocol(transaction->orig_request); + + transaction = NULL; + + if (transport==NULL) + i = _eXosip_build_request_within_dialog (sub, "SUBSCRIBE", jd->d_dialog, "UDP"); + else + i = _eXosip_build_request_within_dialog (sub, "SUBSCRIBE", jd->d_dialog, transport); + + if (i != 0) + return -2; + + return 0; +} + +int +eXosip_subscribe_send_refresh_request (int did, osip_message_t * sub) +{ + eXosip_dialog_t *jd = NULL; + eXosip_subscribe_t *js = NULL; + + osip_transaction_t *transaction; + osip_event_t *sipevent; + int i; + + if (did > 0) + { + eXosip_subscribe_dialog_find (did, &js, &jd); + } + if (jd == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No subscribe here?\n")); + osip_message_free (sub); + return -1; + } + + transaction = NULL; + transaction = eXosip_find_last_out_subscribe (js, jd); + + if (transaction != NULL) + { + if (transaction->state != NICT_TERMINATED && + transaction->state != NIST_TERMINATED && + transaction->state != NICT_COMPLETED && + transaction->state != NIST_COMPLETED) + { + osip_message_free (sub); + return -1; + } + transaction = NULL; + } + + transaction = NULL; + i = osip_transaction_init (&transaction, NICT, eXosip.j_osip, sub); + + if (i != 0) + { + osip_message_free (sub); + return -2; + } + + _eXosip_subscribe_set_refresh_interval (js, sub); + osip_list_add (jd->d_out_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage (sub); + sipevent->transactionid = transaction->transactionid; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, jd, js, NULL)); + osip_transaction_add_event (transaction, sipevent); + __eXosip_wakeup (); + return 0; +} + +int +_eXosip_subscribe_send_request_with_credential (eXosip_subscribe_t * js, + eXosip_dialog_t * jd, + osip_transaction_t * out_tr) +{ + osip_transaction_t *tr = NULL; + osip_message_t *msg = NULL; + osip_event_t *sipevent; + + char locip[256]; + int cseq; + char tmp[256]; + osip_via_t *via; + int i; + + if (js == NULL) + return -1; + if (jd != NULL) + { + if (jd->d_out_trs == NULL) + return -1; + } + + if (out_tr == NULL) + { + out_tr = eXosip_find_last_out_subscribe (js, jd); + } + + if (out_tr == NULL + || out_tr->orig_request == NULL || out_tr->last_response == NULL) + return -1; + + osip_message_clone (out_tr->orig_request, &msg); + if (msg == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: could not clone msg for authentication\n")); + return -1; + } + + via = (osip_via_t *) osip_list_get (msg->vias, 0); + if (via == NULL || msg->cseq == NULL || msg->cseq->number == NULL) + { + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: missing via or cseq header\n")); + return -1; + } + + /* increment cseq */ + cseq = atoi (msg->cseq->number); + osip_free (msg->cseq->number); + msg->cseq->number = strdup_printf ("%i", cseq + 1); + if (jd != NULL && jd->d_dialog != NULL) + { + jd->d_dialog->local_cseq++; + } + + osip_list_remove (msg->vias, 0); + osip_via_free (via); + i = _eXosip_find_protocol(out_tr->orig_request); + if (i==IPPROTO_UDP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, + sizeof (locip)); + if (eXosip.net_interfaces[0].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/UDP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/UDP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[0].net_port, via_branch_new_random ()); + } + else if (i==IPPROTO_TCP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[1].net_ip_family, locip, + sizeof (locip)); + if (eXosip.net_interfaces[1].net_ip_family == AF_INET6) + snprintf (tmp, 256, "SIP/2.0/TCP [%s]:%s;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, via_branch_new_random ()); + else + snprintf (tmp, 256, "SIP/2.0/TCP %s:%s;rport;branch=z9hG4bK%u", + locip, eXosip.net_interfaces[1].net_port, via_branch_new_random ()); + } + else + { + /* tls? */ + osip_message_free (msg); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol\n")); + return -1; + } + + osip_via_init (&via); + osip_via_parse (via, tmp); + osip_list_add (msg->vias, via, 0); + + eXosip_add_authentication_information (msg, out_tr->last_response); + osip_message_force_update (msg); + + i = osip_transaction_init (&tr, NICT, eXosip.j_osip, msg); + + if (i != 0) + { + osip_message_free (msg); + return -1; + } + + if (out_tr == js->s_out_tr) + { + /* replace with the new tr */ + osip_list_add (eXosip.j_transactions, js->s_out_tr, 0); + js->s_out_tr = tr; + } else + { + /* add the new tr for the current dialog */ + osip_list_add (jd->d_out_trs, tr, 0); + } + + sipevent = osip_new_outgoing_sipmessage (msg); + + osip_transaction_set_your_instance (tr, __eXosip_new_jinfo (NULL, jd, js, NULL)); + osip_transaction_add_event (tr, sipevent); + + eXosip_update (); /* fixed? */ + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/eXtransport.c b/exosip2/eXtransport.c new file mode 100644 index 0000000000000000000000000000000000000000..2624ab8a928396b2dd87f9d7e9453ec539cf84fc --- /dev/null +++ b/exosip2/eXtransport.c @@ -0,0 +1,279 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +char *_eXosip_transport_protocol(osip_message_t *msg) +{ + osip_via_t *via; + via = (osip_via_t *) osip_list_get (msg->vias, 0); + if (via == NULL || via->protocol == NULL) + return NULL; + return via->protocol; +} + +int _eXosip_find_protocol(osip_message_t *msg) +{ + osip_via_t *via; + via = (osip_via_t *) osip_list_get (msg->vias, 0); + if (via == NULL || via->protocol == NULL) + return -1; + else if (0==osip_strcasecmp(via->protocol, "UDP")) + return IPPROTO_UDP; + else if (0==osip_strcasecmp(via->protocol, "TCP")) + return IPPROTO_TCP; + return -1;; +} + +int _eXosip_tcp_find_socket(char *host, int port) +{ + int pos; + struct eXosip_net *net; + + net = &eXosip.net_interfaces[1]; + + for (pos=0;pos<EXOSIP_MAX_SOCKETS;pos++) + { + if (net->net_socket_tab[pos].socket!=0) + { + if (0==osip_strcasecmp(net->net_socket_tab[pos].remote_ip, host) + && port == net->net_socket_tab[pos].remote_port) + return net->net_socket_tab[pos].socket; + } + } + return -1; +} + +int _eXosip_tcp_connect_socket(char *host, int port) +{ + int pos; + struct eXosip_net *net; + + int res; + struct addrinfo *addrinfo = NULL; + struct addrinfo *curinfo; + int sock = -1; + + net = &eXosip.net_interfaces[1]; + + for (pos=0;pos<EXOSIP_MAX_SOCKETS;pos++) + { + if (net->net_socket_tab[pos].socket==0) + { + break; + } + } + + if (pos==EXOSIP_MAX_SOCKETS) + return -1; + + res = eXosip_get_addrinfo(&addrinfo, host, port, IPPROTO_TCP); + if (res) + return -1; + + + for (curinfo = addrinfo; curinfo; curinfo = curinfo->ai_next) + { + if (curinfo->ai_protocol && curinfo->ai_protocol != IPPROTO_TCP) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: Skipping protocol %d\n", + curinfo->ai_protocol)); + continue; + } + + sock = (int)socket(curinfo->ai_family, curinfo->ai_socktype, + curinfo->ai_protocol); + if (sock < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: Cannot create socket!\n", + strerror(errno))); + continue; + } + + if (curinfo->ai_family == AF_INET6) + { +#ifdef IPV6_V6ONLY + if (setsockopt_ipv6only(sock)) + { + close(sock); + sock = -1; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: Cannot set socket option!\n", + strerror(errno))); + continue; + } +#endif /* IPV6_V6ONLY */ + } + +#if 0 + res = bind (sock, (struct sockaddr*)&net->ai_addr, curinfo->ai_addrlen); + if (res < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: Cannot bind socket %s\n", + strerror(errno))); + close(sock); + sock = -1; + continue; + } +#endif + + res = connect (sock, curinfo->ai_addr, curinfo->ai_addrlen); + if (res < 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: Cannot bind socket node:%s family:%d %s\n", + host, curinfo->ai_family, strerror(errno))); + close(sock); + sock = -1; + continue; + } + + break; + } + + freeaddrinfo(addrinfo); + + if (sock>0) + { + net->net_socket_tab[pos].socket = sock; + osip_strncpy(net->net_socket_tab[pos].remote_ip, host, + sizeof(net->net_socket_tab[pos].remote_ip)-1); + net->net_socket_tab[pos].remote_port = port; + return sock; + } + + return -1; +} + + +int eXosip_transport_set(osip_message_t *msg, const char *transport) +{ + osip_via_t *via; + + via = (osip_via_t *) osip_list_get (msg->vias, 0); + if (via == NULL || via->protocol == NULL) + return -1; + + if (0==osip_strcasecmp(via->protocol, transport)) + return 0; + + osip_free(via->protocol); + via->protocol = osip_strdup(transport); + return 0; +} + +int _eXosip_recvfrom(int s, char *buf, int len, unsigned int flags, struct sockaddr *from, socklen_t *fromlen) +{ + int message_size=0; + int length_done=0; + int real_size=0; + int i; + int extra_data_discarded; + + if (!eXosip.http_port) + { + return recvfrom(s, buf, len, flags, from, fromlen); + } + + + /* we get the size of the HTTP data */ + i = recv (eXosip.net_interfaces[0].net_socket, (char *) &(message_size), 4, 0); + + real_size = message_size; + if (message_size<0) + { + return -1; /* Connection error? */ + } + if (message_size==0) + { + buf[0]='\0'; + return 0; + } + if (message_size>len-1) + message_size = len-1; + + length_done=0; + + i = recv (eXosip.net_interfaces[0].net_socket, buf, message_size, 0); + length_done = i; + + if (length_done==real_size) + { + return length_done; + } + + if (length_done<message_size) + { + /* continue reading up to message_size */ + while (length_done<message_size) + { + i = recv (eXosip.net_interfaces[0].net_socket, buf+length_done, message_size-length_done, 0); + length_done = length_done+i; + } + } + + extra_data_discarded = length_done; + while (extra_data_discarded<real_size) + { + char buf2[2048]; + /* We have to discard the end of data... up to the next message */ + i = recv (eXosip.net_interfaces[0].net_socket, buf2, 2048, 0); + extra_data_discarded = extra_data_discarded+i; + } + return length_done; +} + +int _eXosip_sendto(int s, const void* buf, size_t len, int flags, + const struct sockaddr* to, socklen_t tolen) +{ + int i; + char buf2[10000]; + + if (!eXosip.http_port) + { + i = sendto(s, buf, len, flags, to, tolen); + return i; + } + + memset(buf2, '\0', sizeof(buf2)); + memcpy(buf2, &len, sizeof(int)); + memcpy(buf2+sizeof(int), buf, len); + + i = send(s, (char *) buf2, len+sizeof(int), 0); /* use TCP connection to proxy */ + if (i>0) + i=i-sizeof(int); + + return i; +} \ No newline at end of file diff --git a/exosip2/eXutils.c b/exosip2/eXutils.c new file mode 100644 index 0000000000000000000000000000000000000000..764209695b783d1957fdba62ae8fba608829ffef --- /dev/null +++ b/exosip2/eXutils.c @@ -0,0 +1,694 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include <osipparser2/osip_port.h> +#include "eXosip2.h" + +extern eXosip_t eXosip; + +#ifdef WIN32 + +/* You need the Platform SDK to compile this. */ +#include <Windows.h> +#include <Iphlpapi.h> + +int +ppl_dns_get_local_fqdn (char **servername, char **serverip, + char **netmask, unsigned int WIN32_interface) +{ + unsigned int pos; + + *servername = NULL; /* no name on win32? */ + *serverip = NULL; + *netmask = NULL; + + /* First, try to get the interface where we should listen */ + { + DWORD size_of_iptable = 0; + PMIB_IPADDRTABLE ipt; + PMIB_IFROW ifrow; + + if (GetIpAddrTable (NULL, &size_of_iptable, TRUE) == ERROR_INSUFFICIENT_BUFFER) + { + ifrow = (PMIB_IFROW) _alloca (sizeof (MIB_IFROW)); + ipt = (PMIB_IPADDRTABLE) _alloca (size_of_iptable); + if (ifrow == NULL || ipt == NULL) + { + /* not very usefull to continue */ + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, + "ERROR alloca failed\r\n")); + return -1; + } + + if (!GetIpAddrTable (ipt, &size_of_iptable, TRUE)) + { + /* look for the best public interface */ + + for (pos = 0; pos < ipt->dwNumEntries && *netmask == NULL; ++pos) + { + /* index is */ + struct in_addr addr; + struct in_addr mask; + + ifrow->dwIndex = ipt->table[pos].dwIndex; + if (GetIfEntry (ifrow) == NO_ERROR) + { + switch (ifrow->dwType) + { + case MIB_IF_TYPE_LOOPBACK: + /* break; */ + case MIB_IF_TYPE_ETHERNET: + default: + addr.s_addr = ipt->table[pos].dwAddr; + mask.s_addr = ipt->table[pos].dwMask; + if (ipt->table[pos].dwIndex == WIN32_interface) + { + *servername = NULL; /* no name on win32? */ + *serverip = osip_strdup (inet_ntoa (addr)); + *netmask = osip_strdup (inet_ntoa (mask)); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Interface ethernet: %s/%s\r\n", + *serverip, *netmask)); + break; + } + } + } + } + } + } + } + + if (*serverip == NULL || *netmask == NULL) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, + "ERROR No network interface found\r\n")); + return -1; + } + + return 0; +} + +int +eXosip_guess_ip_for_via (int family, char *address, int size) +{ + /* w2000 and W95/98 */ + unsigned long best_interface_index; + DWORD hr; + + /* NT4 (sp4 only?) */ + PMIB_IPFORWARDTABLE ipfwdt; + DWORD siz_ipfwd_table = 0; + unsigned int ipf_cnt; + + address[0] = '\0'; + best_interface_index = -1; + /* w2000 and W95/98 only */ + + hr = GetBestInterface (inet_addr ("217.12.3.11"), &best_interface_index); + if (hr) + { + LPVOID lpMsgBuf; + + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + hr, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) & lpMsgBuf, 0, NULL); + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, + "GetBestInterface: %s\r\n", lpMsgBuf)); + best_interface_index = -1; + } + + if (best_interface_index != -1) + { /* probably W2000 or W95/W98 */ + char *servername; + char *serverip; + char *netmask; + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Default Interface found %i\r\n", + best_interface_index)); + + if (0 == ppl_dns_get_local_fqdn (&servername, &serverip, &netmask, + best_interface_index)) + { + osip_strncpy (address, serverip, size - 1); + osip_free (servername); + osip_free (serverip); + osip_free (netmask); + return 0; + } + return -1; + } + + + if (!GetIpForwardTable (NULL, &siz_ipfwd_table, FALSE) == + ERROR_INSUFFICIENT_BUFFER + || !(ipfwdt = (PMIB_IPFORWARDTABLE) alloca (siz_ipfwd_table))) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Allocation error\r\n")); + return -1; + } + + + /* NT4 (sp4 support only?) */ + if (!GetIpForwardTable (ipfwdt, &siz_ipfwd_table, FALSE)) + { + for (ipf_cnt = 0; ipf_cnt < ipfwdt->dwNumEntries; ++ipf_cnt) + { + if (ipfwdt->table[ipf_cnt].dwForwardDest == 0) + { /* default gateway found */ + char *servername; + char *serverip; + char *netmask; + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Default Interface found %i\r\n", + ipfwdt->table[ipf_cnt].dwForwardIfIndex)); + + if (0 == ppl_dns_get_local_fqdn (&servername, + &serverip, + &netmask, + ipfwdt->table[ipf_cnt]. + dwForwardIfIndex)) + { + osip_strncpy (address, serverip, size); + osip_free (servername); + osip_free (serverip); + osip_free (netmask); + return 0; + } + return -1; + } + } + + } + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, + "Please define a default network interface.\r\n")); +#ifdef WANT_INTERFACE_ANYWAY + + + /* NT4 (sp4 support only?) */ + if (!GetIpForwardTable (ipfwdt, &siz_ipfwd_table, FALSE)) + { + for (ipf_cnt = 0; ipf_cnt < ipfwdt->dwNumEntries; ++ipf_cnt) + { + char *servername; + char *serverip; + char *netmask; + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Default Interface found %i\r\n", + ipfwdt->table[ipf_cnt].dwForwardIfIndex)); + + if (0 == ppl_dns_get_local_fqdn (&servername, + &serverip, + &netmask, + ipfwdt->table[ipf_cnt]. + dwForwardIfIndex)) + { + /* search for public */ + if (eXosip_is_public_address(serverip) == 0) + { + osip_strncpy (address, serverip, size); + osip_free (servername); + osip_free (serverip); + osip_free (netmask); + return 0; + } + osip_free (servername); + osip_free (serverip); + osip_free (netmask); + } + } + } + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "No public interface found. searching private\r\n")); + + /* NT4 (sp4 support only?) */ + if (!GetIpForwardTable (ipfwdt, &siz_ipfwd_table, FALSE)) + { + for (ipf_cnt = 0; ipf_cnt < ipfwdt->dwNumEntries; ++ipf_cnt) + { + char *servername; + char *serverip; + char *netmask; + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Default Interface found %i\r\n", + ipfwdt->table[ipf_cnt].dwForwardIfIndex)); + + if (0 == ppl_dns_get_local_fqdn (&servername, + &serverip, + &netmask, + ipfwdt->table[ipf_cnt]. + dwForwardIfIndex)) + { + osip_strncpy (address, serverip, size); + osip_free (servername); + osip_free (serverip); + osip_free (netmask); + return 0; + } + } + } + + { + char *lo = osip_strdup("127.0.0.1"); + osip_strncpy (address, lo, size); + osip_free(lo); + return 0; + } + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "No interface found. returning 127.0.0.1\r\n")); + /* no default gateway interface found */ + return 0; +#else + return -1; +#endif /* WANT_INTERFACE_ANYWAY */ +} + + +#else /* sun, *BSD, linux, and other? */ + + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <sys/ioctl.h> +#include <net/if.h> +#include <unistd.h> +#include <sys/param.h> + +#include <stdio.h> + +static int ppl_dns_default_gateway_ipv4 (char *address, int size); +static int ppl_dns_default_gateway_ipv6 (char *address, int size); + + +int +eXosip_guess_ip_for_via (int familiy, char *address, int size) +{ + if (familiy == AF_INET6) + { + return ppl_dns_default_gateway_ipv6 (address, size); + } else + { + return ppl_dns_default_gateway_ipv4 (address, size); + } +} + +/* This is a portable way to find the default gateway. + * The ip of the default interface is returned. + */ +static int +ppl_dns_default_gateway_ipv4 (char *address, int size) +{ +#ifdef __APPLE_CC__ + int len; +#else + unsigned int len; +#endif + int sock_rt, on = 1; + struct sockaddr_in iface_out; + struct sockaddr_in remote; + + memset (&remote, 0, sizeof (struct sockaddr_in)); + + remote.sin_family = AF_INET; + remote.sin_addr.s_addr = inet_addr ("217.12.3.11"); + remote.sin_port = htons (11111); + + memset (&iface_out, 0, sizeof (iface_out)); + sock_rt = socket (AF_INET, SOCK_DGRAM, 0); + + if (setsockopt (sock_rt, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) == -1) + { + perror ("DEBUG: [get_output_if] setsockopt(SOL_SOCKET, SO_BROADCAST"); + close (sock_rt); + return -1; + } + + if (connect + (sock_rt, (struct sockaddr *) &remote, sizeof (struct sockaddr_in)) == -1) + { + perror ("DEBUG: [get_output_if] connect"); + close (sock_rt); + return -1; + } + + len = sizeof (iface_out); + if (getsockname (sock_rt, (struct sockaddr *) &iface_out, &len) == -1) + { + perror ("DEBUG: [get_output_if] getsockname"); + close (sock_rt); + return -1; + } + + close (sock_rt); + if (iface_out.sin_addr.s_addr == 0) + { /* what is this case?? */ + return -1; + } + osip_strncpy (address, inet_ntoa (iface_out.sin_addr), size - 1); + return 0; +} + + +/* This is a portable way to find the default gateway. + * The ip of the default interface is returned. + */ +static int +ppl_dns_default_gateway_ipv6 (char *address, int size) +{ +#ifdef __APPLE_CC__ + int len; +#else + unsigned int len; +#endif + int sock_rt, on = 1; + struct sockaddr_in6 iface_out; + struct sockaddr_in6 remote; + + memset (&remote, 0, sizeof (struct sockaddr_in6)); + + remote.sin6_family = AF_INET6; + inet_pton (AF_INET6, "2001:638:500:101:2e0:81ff:fe24:37c6", &remote.sin6_addr); + remote.sin6_port = htons (11111); + + memset (&iface_out, 0, sizeof (iface_out)); + sock_rt = socket (AF_INET6, SOCK_DGRAM, 0); + + if (setsockopt (sock_rt, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) == -1) + { + perror ("DEBUG: [get_output_if] setsockopt(SOL_SOCKET, SO_BROADCAST"); + close (sock_rt); + return -1; + } + + if (connect + (sock_rt, (struct sockaddr *) &remote, sizeof (struct sockaddr_in6)) == -1) + { + perror ("DEBUG: [get_output_if] connect"); + close (sock_rt); + return -1; + } + + len = sizeof (iface_out); + if (getsockname (sock_rt, (struct sockaddr *) &iface_out, &len) == -1) + { + perror ("DEBUG: [get_output_if] getsockname"); + close (sock_rt); + return -1; + } + close (sock_rt); + + if (iface_out.sin6_addr.s6_addr == 0) + { /* what is this case?? */ + return -1; + } + inet_ntop (AF_INET6, (const void *) &iface_out.sin6_addr, address, size - 1); + return 0; +} + +#endif + +int +eXosip_get_localip_for (const char *address_to_reach, char *loc, int size) +{ + int err, tmp; + struct addrinfo hints; + struct addrinfo *res = NULL; + struct sockaddr_storage addr; + int sock; + +#ifdef __APPLE_CC__ + int s; +#else + socklen_t s; +#endif +#ifdef MAXHOSTNAMELEN + if (size > MAXHOSTNAMELEN) + size = MAXHOSTNAMELEN; +#else + if (size > 256) + size = 256; +#endif + if (eXosip.forced_localip) + { + if (size > sizeof (eXosip.net_interfaces[0].net_firewall_ip)) + size = sizeof (eXosip.net_interfaces[0].net_firewall_ip); + strncpy (loc, eXosip.net_interfaces[0].net_firewall_ip, size); + return 0; + } + + strcpy (loc, "127.0.0.1"); /* always fallback to local loopback */ + + memset (&hints, 0, sizeof (hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME; */ + err = getaddrinfo (address_to_reach, "5060", &hints, &res); + if (err != 0) + { + eXosip_trace (OSIP_ERROR, + ("Error in getaddrinfo for %s: %s\n", address_to_reach, + gai_strerror (err))); + return -1; + } + if (res == NULL) + { + eXosip_trace (OSIP_ERROR, ("getaddrinfo reported nothing !")); + return -1; + } + sock = socket (res->ai_family, SOCK_DGRAM, 0); + tmp = 1; + err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&tmp, sizeof (int)); + if (err < 0) + { + eXosip_trace (OSIP_ERROR, ("Error in setsockopt: %s\n", strerror (errno))); + return -1; + } + err = connect (sock, res->ai_addr, res->ai_addrlen); + if (err < 0) + { + eXosip_trace (OSIP_ERROR, ("Error in connect: %s\n", strerror (errno))); + freeaddrinfo (res); + close (sock); + return -1; + } + freeaddrinfo (res); + res = NULL; + s = sizeof (addr); + err = getsockname (sock, (struct sockaddr *) &addr, &s); + if (err != 0) + { + eXosip_trace (OSIP_ERROR, ("Error in getsockname: %s\n", strerror (errno))); + close (sock); + return -1; + } + + err = + getnameinfo ((struct sockaddr *) &addr, s, loc, size, NULL, 0, NI_NUMERICHOST); + if (err != 0) + { + eXosip_trace (OSIP_ERROR, ("getnameinfo error:%s", strerror (errno))); + return -1; + } + close (sock); + eXosip_trace (OSIP_INFO1, + ("Outgoing interface to reach %s is %s.\n", address_to_reach, + loc)); + return 0; +} + + +#ifdef SM + +void +eXosip_get_localip_from_via (osip_message_t * mesg, char *locip, int size) +{ + osip_via_t *via = NULL; + char *host; + + via = (osip_via_t *) osip_list_get (mesg->vias, 0); + if (via == NULL) + { + host = "15.128.128.93"; + eXosip_trace (OSIP_ERROR, ("Could not get via:%s")); + } else + host = via->host; + eXosip_get_localip_for (host, locip, size); + +} +#endif + +char * +strdup_printf (const char *fmt, ...) +{ + /* Guess we need no more than 100 bytes. */ + int n, size = 100; + char *p; + va_list ap; + + if ((p = osip_malloc (size)) == NULL) + return NULL; + while (1) + { + /* Try to print in the allocated space. */ + va_start (ap, fmt); +#ifdef WIN32 + n = _vsnprintf (p, size, fmt, ap); +#else + n = vsnprintf (p, size, fmt, ap); +#endif + va_end (ap); + /* If that worked, return the string. */ + if (n > -1 && n < size) + return p; + /* Else try again with more space. */ + if (n > -1) /* glibc 2.1 */ + size = n + 1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + if ((p = realloc (p, size)) == NULL) + return NULL; + } +} + +int +eXosip_get_addrinfo (struct addrinfo **addrinfo, const char *hostname, + int service, int protocol) +{ +#ifndef WIN32 + struct in_addr addr; + struct in6_addr addrv6; +#else + unsigned long int one_inet_addr; +#endif + struct addrinfo hints; + int error; + char portbuf[10]; + + if (hostname==NULL) + return -1; + + if (service != -1) /* -1 for SRV record */ + snprintf (portbuf, sizeof (portbuf), "%i", service); + + memset (&hints, 0, sizeof (hints)); +#ifndef WIN32 + if (inet_pton (AF_INET, hostname, &addr) > 0) + { + /* ipv4 address detected */ + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = PF_INET; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "IPv4 address detected: %s\n", hostname)); + } else if (inet_pton (AF_INET6, hostname, &addrv6) > 0) + { + /* ipv6 address detected */ + /* Do the resolution anyway */ + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_INET6; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "IPv6 address detected: %s\n", hostname)); + } else + { + /* hostname must be resolved */ + hints.ai_flags = AI_CANONNAME; + if (protocol==IPPROTO_UDP) + hints.ai_family = (eXosip.net_interfaces[0].net_ip_family == AF_INET) ? PF_INET : PF_INET6; + else if (protocol==IPPROTO_TCP) + hints.ai_family = (eXosip.net_interfaces[1].net_ip_family == AF_INET) ? PF_INET : PF_INET6; + else + { + hints.ai_family = (eXosip.net_interfaces[0].net_ip_family == AF_INET) ? PF_INET : PF_INET6; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol (default to UDP)\n")); + } + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "Not an IPv4 or IPv6 address: %s\n", hostname)); + } +#else + if ((int) (one_inet_addr = inet_addr (hostname)) == -1) + hints.ai_flags = AI_CANONNAME; + else + hints.ai_flags = AI_NUMERICHOST; + +#ifdef IPV6_SUPPORT + hints.ai_family = PF_UNSPEC; /* ipv6 support */ +#else + hints.ai_family = PF_INET; /* ipv4 only support */ +#endif + +#endif + + if (protocol==IPPROTO_UDP) + hints.ai_socktype = SOCK_DGRAM; + else + hints.ai_socktype = SOCK_STREAM; + + hints.ai_protocol = protocol; /* IPPROTO_UDP or IPPROTO_TCP */ + if (service == -1) /* -1 for SRV record */ + { + error = getaddrinfo (hostname, "sip", &hints, addrinfo); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "SRV resolution with udp-sip-%s\n", hostname)); + } else + { + error = getaddrinfo (hostname, portbuf, &hints, addrinfo); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "DNS resolution with %s:%i\n", hostname, service)); + } + if (error || *addrinfo == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "getaddrinfo failure. %s:%s (%s)\n", hostname, portbuf, + gai_strerror (error))); + return -1; + } + + return 0; +} + diff --git a/exosip2/inet_ntop.c b/exosip2/inet_ntop.c new file mode 100644 index 0000000000000000000000000000000000000000..d3d765c263801a8f322ce55b017d03d313c9ff3b --- /dev/null +++ b/exosip2/inet_ntop.c @@ -0,0 +1,217 @@ +/* This is from the BIND 4.9.4 release, modified to compile by itself */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#if defined(WIN32) + +#include <osipparser2/osip_port.h> +#include "eXosip2.h" + +#include <windowsx.h> +#include <winsock2.h> +#include <Ws2tcpip.h> +#include <Iphlpapi.h> + +#include "inet_ntop.h" + +/* added by adm */ +/* + * the definitions below are valid for 32-bit architectures and will have to + * be adjusted for 16- or 64-bit architectures + */ +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned long in_addr_t; + +/* !added by amd */ + +#define IN6ADDRSZ 16 +#define INT16SZ 2 + +#ifndef AF_INET6 +#define AF_INET6 AF_MAX+1 /* just to let this compile */ +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *_inet_ntop4(const u_char *src, char *dst, size_t size); +static const char *_inet_ntop6(const u_char *src, char *dst, size_t size); + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +_inet_ntop(af, src, dst, size) + int af; + const void *src; + char *dst; + size_t size; +{ + switch (af) { + case AF_INET: + return (_inet_ntop4(src, dst, size)); + case AF_INET6: + return (_inet_ntop6(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +_inet_ntop4(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + sprintf(tmp, fmt, src[0], src[1], src[2], src[3]); + if ((size_t)strlen(tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +_inet_ntop6(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + uint32_t words[IN6ADDRSZ / INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, 0, sizeof words); + for (i = 0; i < IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!_inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + sprintf(tp, "%x", words[i]); + tp += strlen(tp); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t) (tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +#endif + diff --git a/exosip2/inet_ntop.h b/exosip2/inet_ntop.h new file mode 100644 index 0000000000000000000000000000000000000000..d965806f77c7f9e1fbbc6286d7a98906840d9c52 --- /dev/null +++ b/exosip2/inet_ntop.h @@ -0,0 +1,21 @@ + +#if defined(WIN32) + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#endif + + +const char *_inet_ntop(int af, const void *src, char *dst, size_t size); + +#define inet_ntop _inet_ntop + +#if defined(__cplusplus) +} +#endif + +#endif /* WIN32 */ diff --git a/exosip2/jauth.c b/exosip2/jauth.c new file mode 100644 index 0000000000000000000000000000000000000000..63c9539d9d1695c0ab13eec1e2c4de49d188cea6 --- /dev/null +++ b/exosip2/jauth.c @@ -0,0 +1,489 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" +#include <eXosip2/eXosip.h> + +#include <osip2/osip_mt.h> +#include <osip2/osip_condv.h> + +/* #include <osip2/global.h> */ +#include <osipparser2/osip_md5.h> + +/* TAKEN from rcf2617.txt */ + +#define HASHLEN 16 +typedef char HASH[HASHLEN]; + +#define HASHHEXLEN 32 +typedef char HASHHEX[HASHHEXLEN + 1]; + +#define IN +#define OUT + +extern eXosip_t eXosip; + +/* Private functions */ +static void CvtHex (IN HASH Bin, OUT HASHHEX Hex); +static void DigestCalcHA1 (IN const char *pszAlg, IN const char *pszUserName, + IN const char *pszRealm, + IN const char *pszPassword, + IN const char *pszNonce, IN const char *pszCNonce, + OUT HASHHEX SessionKey); +static void DigestCalcResponse (IN HASHHEX HA1, IN const char *pszNonce, + IN const char *pszNonceCount, + IN const char *pszCNonce, + IN const char *pszQop, + IN const char *pszMethod, + IN const char *pszDigestUri, + IN HASHHEX HEntity, OUT HASHHEX Response); + +static void +CvtHex (IN HASH Bin, OUT HASHHEX Hex) +{ + unsigned short i; + unsigned char j; + + for (i = 0; i < HASHLEN; i++) + { + j = (Bin[i] >> 4) & 0xf; + if (j <= 9) + Hex[i * 2] = (j + '0'); + else + Hex[i * 2] = (j + 'a' - 10); + j = Bin[i] & 0xf; + if (j <= 9) + Hex[i * 2 + 1] = (j + '0'); + else + Hex[i * 2 + 1] = (j + 'a' - 10); + }; + Hex[HASHHEXLEN] = '\0'; +} + +/* calculate H(A1) as per spec */ +static void +DigestCalcHA1 (IN const char *pszAlg, + IN const char *pszUserName, + IN const char *pszRealm, + IN const char *pszPassword, + IN const char *pszNonce, + IN const char *pszCNonce, OUT HASHHEX SessionKey) +{ + MD5_CTX Md5Ctx; + HASH HA1; + + MD5Init (&Md5Ctx); + MD5Update (&Md5Ctx, (unsigned char *) pszUserName, strlen (pszUserName)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszRealm, strlen (pszRealm)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszPassword, strlen (pszPassword)); + MD5Final ((unsigned char *) HA1, &Md5Ctx); + if ((pszAlg != NULL) && osip_strcasecmp (pszAlg, "md5-sess") == 0) + { + MD5Init (&Md5Ctx); + MD5Update (&Md5Ctx, (unsigned char *) HA1, HASHLEN); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszNonce, strlen (pszNonce)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszCNonce, strlen (pszCNonce)); + MD5Final ((unsigned char *) HA1, &Md5Ctx); + } + CvtHex (HA1, SessionKey); +} + +/* calculate request-digest/response-digest as per HTTP Digest spec */ +static void +DigestCalcResponse (IN HASHHEX HA1, /* H(A1) */ + IN const char *pszNonce, /* nonce from server */ + IN const char *pszNonceCount, /* 8 hex digits */ + IN const char *pszCNonce, /* client nonce */ + IN const char *pszQop, /* qop-value: "", "auth", "auth-int" */ + IN const char *pszMethod, /* method from the request */ + IN const char *pszDigestUri, /* requested URL */ + IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ + OUT HASHHEX Response + /* request-digest or response-digest */ ) +{ + MD5_CTX Md5Ctx; + HASH HA2; + HASH RespHash; + HASHHEX HA2Hex; + + /* calculate H(A2) */ + MD5Init (&Md5Ctx); + MD5Update (&Md5Ctx, (unsigned char *) pszMethod, strlen (pszMethod)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszDigestUri, strlen (pszDigestUri)); + + if (pszQop != NULL) + { + + /*#define AUTH_INT_SUPPORT *//* experimental */ +#ifdef AUTH_INT_SUPPORT /* experimental */ + char *index = strchr (pszQop, 'i'); + + while (index != NULL && index - pszQop >= 5 && strlen (index) >= 3) + { + if (osip_strncasecmp (index - 5, "auth-int", 8) == 0) + { + goto auth_withqop; + } + index = strchr (index + 1, 'i'); + } + + strchr (pszQop, 'a'); + while (index != NULL && strlen (index) >= 4) + { + if (osip_strncasecmp (index - 5, "auth", 4) == 0) + { + /* and in the case of a unknown token + like auth1. It is not auth, but this + implementation will think it is!?? + This is may not happen but it's a bug! + */ + goto auth_withqop; + } + index = strchr (index + 1, 'a'); + } +#endif + goto auth_withoutqop; + + }; + +auth_withoutqop: + MD5Final ((unsigned char *) HA2, &Md5Ctx); + CvtHex (HA2, HA2Hex); + + /* calculate response */ + MD5Init (&Md5Ctx); + MD5Update (&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszNonce, strlen (pszNonce)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + + goto end; + +#ifdef AUTH_INT_SUPPORT /* experimental */ +auth_withqop: +#endif + + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) HEntity, HASHHEXLEN); + MD5Final ((unsigned char *) HA2, &Md5Ctx); + CvtHex (HA2, HA2Hex); + + /* calculate response */ + MD5Init (&Md5Ctx); + MD5Update (&Md5Ctx, (unsigned char *) HA1, HASHHEXLEN); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszNonce, strlen (pszNonce)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszNonceCount, strlen (pszNonceCount)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszCNonce, strlen (pszCNonce)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + MD5Update (&Md5Ctx, (unsigned char *) pszQop, strlen (pszQop)); + MD5Update (&Md5Ctx, (unsigned char *) ":", 1); + +end: + MD5Update (&Md5Ctx, (unsigned char *) HA2Hex, HASHHEXLEN); + MD5Final ((unsigned char *) RespHash, &Md5Ctx); + CvtHex (RespHash, Response); +} + + +int +__eXosip_create_authorization_header (osip_message_t * previous_answer, + const char *rquri, const char *username, + const char *passwd, const char *ha1, + osip_authorization_t ** auth, + const char *method) +{ + osip_authorization_t *aut; + osip_www_authenticate_t *wa = NULL; + + osip_message_get_www_authenticate (previous_answer, 0, &wa); + + /* make some test */ + if (passwd == NULL) + return -1; + if (wa == NULL || wa->auth_type == NULL + || (wa->realm == NULL) || (wa->nonce == NULL)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "www_authenticate header is not acceptable.\n")); + return -1; + } + if (0 != osip_strcasecmp ("Digest", wa->auth_type)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Authentication method not supported. (Digest only).\n")); + return -1; + } + /* "MD5" is invalid, but some servers use it. */ + if (wa->algorithm != NULL && 0 != osip_strcasecmp ("MD5", wa->algorithm) + && 0 != osip_strcasecmp ("\"MD5\"", wa->algorithm)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Authentication method not supported. (Digest only).\n")); + return -1; + } + if (0 != osip_authorization_init (&aut)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "allocation with authorization_init failed.\n")); + return -1; + } + + /* just copy some feilds from response to new request */ + osip_authorization_set_auth_type (aut, osip_strdup ("Digest")); + osip_authorization_set_realm (aut, + osip_strdup (osip_www_authenticate_get_realm + (wa))); + osip_authorization_set_nonce (aut, + osip_strdup (osip_www_authenticate_get_nonce + (wa))); + if (osip_www_authenticate_get_opaque (wa) != NULL) + osip_authorization_set_opaque (aut, + osip_strdup + (osip_www_authenticate_get_opaque (wa))); + /* copy the username field in new request */ + aut->username = osip_malloc (strlen (username) + 3); + sprintf (aut->username, "\"%s\"", username); + + { + char *tmp = osip_malloc (strlen (rquri) + 3); + + sprintf (tmp, "\"%s\"", rquri); + osip_authorization_set_uri (aut, tmp); + } + + osip_authorization_set_algorithm (aut, osip_strdup ("MD5")); + + { + char *pszNonce = + osip_strdup_without_quote (osip_www_authenticate_get_nonce (wa)); + char *pszCNonce = NULL; + const char *pszUser = username; + char *pszRealm = + osip_strdup_without_quote (osip_authorization_get_realm (aut)); + const char *pszPass = NULL; + char *pszAlg = osip_strdup ("MD5"); + char *szNonceCount = NULL; + const char *pszMethod = method; /* previous_answer->cseq->method; */ + char *pszQop = NULL; + const char *pszURI = rquri; + + HASHHEX HA1; + HASHHEX HA2 = ""; + HASHHEX Response; + const char *pha1 = NULL; + + pszPass = passwd; + if (osip_authorization_get_nonce_count (aut) != NULL) + szNonceCount = osip_strdup (osip_authorization_get_nonce_count (aut)); + if (osip_authorization_get_message_qop (aut) != NULL) + pszQop = osip_strdup (osip_authorization_get_message_qop (aut)); + + if (ha1 && ha1[0]) + { + /* Depending on algorithm=md5 */ + pha1 = ha1; + } + else + { + DigestCalcHA1 (pszAlg, pszUser, pszRealm, pszPass, pszNonce, pszCNonce, HA1); + pha1 = HA1; + } + + DigestCalcResponse ((char *)pha1, pszNonce, szNonceCount, pszCNonce, pszQop, + pszMethod, pszURI, HA2, Response); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Response in authorization |%s|\n", Response)); + { + char *resp = osip_malloc (35); + + sprintf (resp, "\"%s\"", Response); + osip_authorization_set_response (aut, resp); + } + osip_free (pszAlg); /* xkd, 2004-5-13 */ + osip_free (pszNonce); + osip_free (pszCNonce); + osip_free (pszRealm); + osip_free (pszQop); + osip_free (szNonceCount); + } + + *auth = aut; + return 0; +} + +int +__eXosip_create_proxy_authorization_header (osip_message_t * previous_answer, + const char *rquri, + const char *username, + const char *passwd, + const char *ha1, + osip_proxy_authorization_t ** auth, + const char *method) +{ + osip_proxy_authorization_t *aut; + osip_proxy_authenticate_t *wa; + + osip_message_get_proxy_authenticate (previous_answer, 0, &wa); + + /* make some test */ + if (passwd == NULL) + return -1; + if (wa == NULL || wa->auth_type == NULL + || (wa->realm == NULL) || (wa->nonce == NULL)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "www_authenticate header is not acceptable.\n")); + return -1; + } + if (0 != osip_strcasecmp ("Digest", wa->auth_type)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Authentication method not supported. (Digest only).\n")); + return -1; + } + /* "MD5" is invalid, but some servers use it. */ + if (wa->algorithm != NULL && 0 != osip_strcasecmp ("MD5", wa->algorithm) + && 0 != osip_strcasecmp ("\"MD5\"", wa->algorithm)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Authentication method not supported. (MD5 Digest only).\n")); + return -1; + } + if (0 != osip_proxy_authorization_init (&aut)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "allocation with authorization_init failed.\n")); + return -1; + } + + /* just copy some feilds from response to new request */ + osip_proxy_authorization_set_auth_type (aut, osip_strdup ("Digest")); + osip_proxy_authorization_set_realm (aut, + osip_strdup + (osip_proxy_authenticate_get_realm (wa))); + osip_proxy_authorization_set_nonce (aut, + osip_strdup + (osip_proxy_authenticate_get_nonce (wa))); + if (osip_proxy_authenticate_get_opaque (wa) != NULL) + osip_proxy_authorization_set_opaque (aut, + osip_strdup + (osip_proxy_authenticate_get_opaque + (wa))); + /* copy the username field in new request */ + aut->username = osip_malloc (strlen (username) + 3); + sprintf (aut->username, "\"%s\"", username); + + { + char *tmp = osip_malloc (strlen (rquri) + 3); + + sprintf (tmp, "\"%s\"", rquri); + osip_proxy_authorization_set_uri (aut, tmp); + } + osip_proxy_authorization_set_algorithm (aut, osip_strdup ("MD5")); + + { + char *pszNonce = NULL; + char *pszCNonce = NULL; + const char *pszUser = username; + char *pszRealm = + osip_strdup_without_quote (osip_proxy_authorization_get_realm (aut)); + const char *pszPass = NULL; + char *pszAlg = osip_strdup ("MD5"); + char *szNonceCount = NULL; + char *pszMethod = (char *)method; /* previous_answer->cseq->method; */ + char *pszQop = NULL; + const char *pszURI = rquri; + + HASHHEX HA1; + HASHHEX HA2 = ""; + HASHHEX Response; + const char *pha1 = NULL; + + pszPass = passwd; + + if (osip_www_authenticate_get_nonce (wa) == NULL) + return -1; + pszNonce = osip_strdup_without_quote (osip_www_authenticate_get_nonce (wa)); + + /* should upgrade szNonceCount */ + /* should add szNonceCount in aut */ + /* should upgrade pszCNonce */ + /* should add pszCNonce in aut */ + + if (osip_proxy_authenticate_get_qop_options (wa) != NULL) + { + szNonceCount = osip_strdup ("00000001"); + /* MUST be incremented on each */ + pszQop = osip_strdup (osip_proxy_authenticate_get_qop_options (wa)); + pszCNonce = osip_strdup ("234abcc436e2667097e7fe6eia53e8dd"); + } + if (ha1 && ha1[0]) + { + /* Depending on algorithm=md5 */ + pha1 = ha1; + } + else + { + DigestCalcHA1 (pszAlg, pszUser, pszRealm, pszPass, pszNonce, pszCNonce, HA1); + pha1 = HA1; + } + DigestCalcResponse ((char *)pha1, pszNonce, szNonceCount, pszCNonce, pszQop, + pszMethod, pszURI, HA2, Response); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO4, NULL, + "Response in proxy_authorization |%s|\n", Response)); + { + char *resp = osip_malloc (35); + + sprintf (resp, "\"%s\"", Response); + osip_proxy_authorization_set_response (aut, resp); + } + osip_free (pszAlg); /* xkd, 2004-5-13 */ + osip_free (pszNonce); + osip_free (pszCNonce); + osip_free (pszRealm); + osip_free (pszQop); + osip_free (szNonceCount); + } + + *auth = aut; + return 0; +} diff --git a/exosip2/jcall.c b/exosip2/jcall.c new file mode 100644 index 0000000000000000000000000000000000000000..cd13c0432ea7d50002f961933cd1851529d6a68b --- /dev/null +++ b/exosip2/jcall.c @@ -0,0 +1,119 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +int +eXosip_call_find (int cid, eXosip_call_t ** jc) +{ + for (*jc = eXosip.j_calls; *jc != NULL; *jc = (*jc)->next) + { + if ((*jc)->c_id == cid) + { + return 0; + } + } + *jc = NULL; + return -1; +} + +int +eXosip_call_init (eXosip_call_t ** jc) +{ + *jc = (eXosip_call_t *) osip_malloc (sizeof (eXosip_call_t)); + if (*jc == NULL) + return -1; + memset (*jc, 0, sizeof (eXosip_call_t)); + + (*jc)->c_id = -1; /* make sure the eXosip_update will assign a valid id to the call */ + return 0; +} + +void +__eXosip_call_remove_dialog_reference_in_call (eXosip_call_t * jc, + eXosip_dialog_t * jd) +{ + eXosip_dialog_t *_jd; + jinfo_t *ji; + + if (jc == NULL) + return; + if (jd == NULL) + return; + + + for (_jd = jc->c_dialogs; _jd != NULL; _jd = _jd->next) + { + if (jd == _jd) + break; + } + if (_jd == NULL) + { + /* dialog not found??? */ + } + + ji = osip_transaction_get_your_instance (jc->c_inc_tr); + if (ji != NULL && ji->jd == jd) + ji->jd = NULL; + ji = osip_transaction_get_your_instance (jc->c_out_tr); + if (ji != NULL && ji->jd == jd) + ji->jd = NULL; +} + +void +eXosip_call_free (eXosip_call_t * jc) +{ + /* ... */ + + eXosip_dialog_t *jd; + + if (jc->response_auth!=NULL) + osip_message_free(jc->response_auth); + + for (jd = jc->c_dialogs; jd != NULL; jd = jc->c_dialogs) + { + REMOVE_ELEMENT (jc->c_dialogs, jd); + eXosip_dialog_free (jd); + } + + __eXosip_delete_jinfo (jc->c_inc_tr); + __eXosip_delete_jinfo (jc->c_out_tr); + if (jc->c_inc_tr != NULL) + osip_list_add (eXosip.j_transactions, jc->c_inc_tr, 0); + if (jc->c_out_tr != NULL) + osip_list_add (eXosip.j_transactions, jc->c_out_tr, 0); + + __eXosip_delete_jinfo (jc->c_inc_options_tr); + __eXosip_delete_jinfo (jc->c_out_options_tr); + if (jc->c_inc_options_tr != NULL) + osip_list_add (eXosip.j_transactions, jc->c_inc_options_tr, 0); + if (jc->c_out_options_tr != NULL) + osip_list_add (eXosip.j_transactions, jc->c_out_options_tr, 0); + + osip_free (jc); + +} diff --git a/exosip2/jcallback.c b/exosip2/jcallback.c new file mode 100644 index 0000000000000000000000000000000000000000..84e9b646b722ca1eb701162182c4118dac52c92c --- /dev/null +++ b/exosip2/jcallback.c @@ -0,0 +1,2053 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include <stdlib.h> + +#ifdef WIN32 +#include <windowsx.h> +#include <winsock2.h> +#include <Ws2tcpip.h> +#include "inet_ntop.h" + +#else +#include <sys/wait.h> +#include <sys/types.h> +#include <unistd.h> +#include <assert.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#endif + +#include <eXosip2/eXosip.h> +#include "eXosip2.h" + +extern eXosip_t eXosip; + + +/* Private functions */ +static void rcvregister_failure (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_ict_kill_transaction (int type, osip_transaction_t * tr); +static void cb_ist_kill_transaction (int type, osip_transaction_t * tr); +static void cb_nict_kill_transaction (int type, osip_transaction_t * tr); +static void cb_nist_kill_transaction (int type, osip_transaction_t * tr); +static void cb_rcvinvite (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcvack (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcvack2 (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcvregister (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_rcvcancel (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcvrequest (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_sndinvite (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_sndack (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_sndregister (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_sndbye (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_sndcancel (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_sndinfo (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_sndoptions (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_sndnotify (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_sndsubscribe (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_sndunkrequest (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_rcv1xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcv2xx_4invite (osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcv2xx_4subscribe (osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcv2xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcv3xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcv4xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcv5xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcv6xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_snd1xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_snd2xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_snd3xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_snd4xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_snd5xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_snd6xx (int type, osip_transaction_t * tr, osip_message_t * sip); +static void cb_rcvresp_retransmission (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_sndreq_retransmission (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_sndresp_retransmission (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_rcvreq_retransmission (int type, osip_transaction_t * tr, + osip_message_t * sip); +static void cb_transport_error (int type, osip_transaction_t * tr, int error); + + +int +cb_snd_message (osip_transaction_t * tr, osip_message_t * sip, char *host, + int port, int out_socket) +{ + int i; + osip_via_t *via; + if (eXosip.net_interfaces[0].net_socket == 0 + && eXosip.net_interfaces[1].net_socket == 0) + return -1; + + if (host == NULL) + { + host = sip->req_uri->host; + if (sip->req_uri->port != NULL) + port = osip_atoi (sip->req_uri->port); + else + port = 5060; + } + + via = (osip_via_t *) osip_list_get(sip->vias, 0); + if (via==NULL || via->protocol==NULL) + return -1; + + i = -1; + if (osip_strcasecmp(via->protocol, "udp")==0) + { + i = cb_udp_snd_message (tr, sip, host, port, out_socket); + } + else + { + i = cb_tcp_snd_message (tr, sip, host, port, out_socket); + } + if (i != 0) + { + return -1; + } + + return 0; + +} + +int +cb_udp_snd_message (osip_transaction_t * tr, osip_message_t * sip, char *host, + int port, int out_socket) +{ + int len = 0; + size_t length = 0; + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + char *message; +#ifdef INET6_ADDRSTRLEN + char ipbuf[INET6_ADDRSTRLEN]; +#else + char ipbuf[46]; +#endif + int i; + struct eXosip_net *net; + + if (eXosip.net_interfaces[0].net_socket == 0) + return -1; + + net = &eXosip.net_interfaces[0]; + + if (eXosip.http_port) + { + i = osip_message_to_str (sip, &message, &length); + + if (i != 0 || length <= 0) + { + return -1; + } + if (0 > + _eXosip_sendto (net->net_socket, (const void *) message, length, 0, + (struct sockaddr *) &addr, len )) + { + /* should reopen connection! */ + osip_free (message); + return -1; + } + return 0; + } + + if (host == NULL) + { + host = sip->req_uri->host; + if (sip->req_uri->port != NULL) + port = osip_atoi (sip->req_uri->port); + else + port = 5060; + } + + i = eXosip_get_addrinfo (&addrinfo, host, port, IPPROTO_UDP); + if (i != 0) + { + return -1; + } + + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + len = addrinfo->ai_addrlen; + + freeaddrinfo (addrinfo); + + i = osip_message_to_str (sip, &message, &length); + + if (i != 0 || length <= 0) + { + return -1; + } + + switch (addr.ss_family) + { + case AF_INET: + inet_ntop(addr.ss_family, &(((struct sockaddr_in*)&addr)->sin_addr), ipbuf, sizeof(ipbuf)); + break; + case AF_INET6: + inet_ntop(addr.ss_family, &(((struct sockaddr_in6*)&addr)->sin6_addr), ipbuf, sizeof(ipbuf)); + break; + default: + strncpy(ipbuf, "(unknown)", sizeof(ipbuf)); + break; + } + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message sent: \n%s (to dest=%s:%i)\n", + message, ipbuf, port)); + if (0 > + _eXosip_sendto (net->net_socket, (const void *) message, length, 0, + (struct sockaddr *) &addr, len )) + { +#ifdef WIN32 + if (WSAECONNREFUSED == WSAGetLastError ()) +#else + if (ECONNREFUSED == errno) +#endif + { + /* This can be considered as an error, but for the moment, + I prefer that the application continue to try sending + message again and again... so we are not in a error case. + Nevertheless, this error should be announced! + ALSO, UAS may not have any other options than retry always + on the same port. + */ + osip_free (message); + return 1; + } else + { + /* SIP_NETWORK_ERROR; */ + osip_free (message); + return -1; + } + } + + + if (eXosip.keep_alive>0) + { + if (MSG_IS_REGISTER(sip)) + { + eXosip_reg_t *reg = NULL; + if (_eXosip_reg_find(®, tr)==0) + { + memcpy (&(reg->addr), &addr, len); + reg->len = len; + } + } + } + + osip_free (message); + return 0; + +} + +int +cb_tcp_snd_message (osip_transaction_t * tr, osip_message_t * sip, char *host, + int port, int out_socket) +{ + size_t length = 0; + char *message; + int i; + struct eXosip_net *net; + if (eXosip.net_interfaces[1].net_socket == 0) + return -1; + + if (host == NULL) + { + host = sip->req_uri->host; + if (sip->req_uri->port != NULL) + port = osip_atoi (sip->req_uri->port); + else + port = 5060; + } + + net = &eXosip.net_interfaces[1]; + + i = osip_message_to_str (sip, &message, &length); + + if (i != 0 || length <= 0) + { + return -1; + } + + /* Step 1: find existing socket to send message */ + if (out_socket<=0) + { + out_socket = _eXosip_tcp_find_socket(host, port); + + /* Step 2: create new socket with host:port */ + if (out_socket<=0) + { + out_socket = _eXosip_tcp_connect_socket(host, port); + } + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message sent: \n%s (to dest=%s:%i)\n", + message, host, port)); + } + else + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message sent: \n%s (reusing REQUEST connection)\n", + message, host, port)); + } + + if (out_socket<=0) + { + return -1; + } + + + if (0 > send (out_socket, (const void *) message, length, 0)) + { +#ifdef WIN32 + if (WSAECONNREFUSED == WSAGetLastError ()) +#else + if (ECONNREFUSED == errno) +#endif + { + /* This can be considered as an error, but for the moment, + I prefer that the application continue to try sending + message again and again... so we are not in a error case. + Nevertheless, this error should be announced! + ALSO, UAS may not have any other options than retry always + on the same port. + */ + osip_free (message); + return 1; + } else + { + /* SIP_NETWORK_ERROR; */ + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "TCP error: \n%s\n", + strerror(errno))); + osip_free (message); + return -1; + } + } + + osip_free (message); + return 0; + +} + +static void +cb_ict_kill_transaction (int type, osip_transaction_t * tr) +{ + int i; + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_ict_kill_transaction (id=%i)\r\n", tr->transactionid)); + + i = osip_remove_transaction (eXosip.j_osip, tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_BUG, NULL, + "cb_ict_kill_transaction Error: Could not remove transaction from the oSIP stack? (id=%i)\r\n", + tr->transactionid)); + } +} + +static void +cb_ist_kill_transaction (int type, osip_transaction_t * tr) +{ + int i; + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_ist_kill_transaction (id=%i)\r\n", tr->transactionid)); + i = osip_remove_transaction (eXosip.j_osip, tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_BUG, NULL, + "cb_ist_kill_transaction Error: Could not remove transaction from the oSIP stack? (id=%i)\r\n", + tr->transactionid)); + } +} + +static void +cb_nict_kill_transaction (int type, osip_transaction_t * tr) +{ + int i; + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_nict_kill_transaction (id=%i)\r\n", tr->transactionid)); + i = osip_remove_transaction (eXosip.j_osip, tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_BUG, NULL, + "cb_nict_kill_transaction Error: Could not remove transaction from the oSIP stack? (id=%i)\r\n", + tr->transactionid)); + } + + if (MSG_IS_REGISTER (tr->orig_request) + && type == OSIP_NICT_KILL_TRANSACTION && tr->last_response == NULL) + { + eXosip_event_t *je; + eXosip_reg_t *jreg = NULL; + + /* find matching j_reg */ + _eXosip_reg_find (&jreg, tr); + if (jreg != NULL) + { + je = eXosip_event_init_for_reg (EXOSIP_REGISTRATION_FAILURE, jreg, tr); + report_event (je, NULL); + } + return; + } + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (jn == NULL && js == NULL) + return; + + /* no answer to a NOTIFY request! */ + if (MSG_IS_NOTIFY (tr->orig_request) + && type == OSIP_NICT_KILL_TRANSACTION && tr->last_response == NULL) + { + /* delete the dialog! */ + REMOVE_ELEMENT (eXosip.j_notifies, jn); + eXosip_notify_free (jn); + return; + } + + if (MSG_IS_NOTIFY (tr->orig_request) + && type == OSIP_NICT_KILL_TRANSACTION + && tr->last_response != NULL && tr->last_response->status_code > 299) + { + /* delete the dialog! */ + if (tr->last_response->status_code != 407 + && tr->last_response->status_code != 401) + { + REMOVE_ELEMENT (eXosip.j_notifies, jn); + eXosip_notify_free (jn); + return; + } + } + + if (MSG_IS_NOTIFY (tr->orig_request) + && type == OSIP_NICT_KILL_TRANSACTION + && tr->last_response != NULL + && tr->last_response->status_code > 199 + && tr->last_response->status_code < 300) + { + if (jn->n_ss_status == EXOSIP_SUBCRSTATE_TERMINATED) + { + /* delete the dialog! */ + REMOVE_ELEMENT (eXosip.j_notifies, jn); + eXosip_notify_free (jn); + return; + } + } + + /* no answer to a SUBSCRIBE request! */ + if (MSG_IS_SUBSCRIBE (tr->orig_request) + && type == OSIP_NICT_KILL_TRANSACTION && tr->last_response == NULL) + { + /* delete the dialog! */ + REMOVE_ELEMENT (eXosip.j_subscribes, js); + eXosip_subscribe_free (js); + return; + } + + /* detect SUBSCRIBE request that close the dialogs! */ + /* expires=0 with MSN */ + if (MSG_IS_SUBSCRIBE (tr->orig_request) && type == OSIP_NICT_KILL_TRANSACTION) + { + osip_header_t *expires; + + osip_message_get_expires (tr->orig_request, 0, &expires); + if (expires == NULL || expires->hvalue == NULL) + { + } else if (0 == strcmp (expires->hvalue, "0")) + { + /* delete the dialog! */ + REMOVE_ELEMENT (eXosip.j_subscribes, js); + eXosip_subscribe_free (js); + return; + } + } +} + +static void +cb_nist_kill_transaction (int type, osip_transaction_t * tr) +{ + int i; + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_nist_kill_transaction (id=%i)\r\n", tr->transactionid)); + i = osip_remove_transaction (eXosip.j_osip, tr); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_BUG, NULL, + "cb_nist_kill_transaction Error: Could not remove transaction from the oSIP stack? (id=%i)\r\n", + tr->transactionid)); + } + +} + +static void +cb_rcvinvite (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcvinvite (id=%i)\n", + tr->transactionid)); +} + +static void +cb_rcvack (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcvack (id=%i)\n", + tr->transactionid)); +} + +static void +cb_rcvack2 (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcvack2 (id=%i)\r\n", + tr->transactionid)); +} + +static void +cb_rcvregister (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_event_t *je; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcvregister (id=%i)\r\n", tr->transactionid)); + + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_NEW, tr); + eXosip_event_add (je); + return; +} + +static void +cb_rcvcancel (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcvcancel (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_rcvrequest (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_notify_t *jn; + eXosip_subscribe_t *js; + + eXosip_event_t *je; + + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcvunkrequest (id=%i)\r\n", tr->transactionid)); + + if (jinfo == NULL) + { + eXosip_event_t *je; + + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_NEW, tr); + eXosip_event_add (je); + return; + } + + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + if (jc == NULL && jn == NULL && js == NULL) + { + eXosip_event_t *je; + + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_NEW, tr); + eXosip_event_add (je); + return; + } + else if (jc!=NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcv? (id=%i)\r\n", tr->transactionid)); + + report_call_event (EXOSIP_CALL_MESSAGE_NEW, jc, jd, tr); + return; + } + else if (jn!=NULL) + { + if (MSG_IS_SUBSCRIBE (sip)) + { + je = eXosip_event_init_for_notify (EXOSIP_IN_SUBSCRIPTION_NEW, jn, jd, tr); + report_event (je, NULL); + return; + } + return; + } + else if (js!=NULL) + { + if (MSG_IS_NOTIFY (sip)) + { + je = eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_NOTIFY, js, jd, tr); + report_event (je, NULL); + return; + } + return; + } +} + +static void +cb_sndinvite (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndinvite (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_sndack (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_sndack (id=%i)\r\n", + tr->transactionid)); +} + +static void +cb_sndregister (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndregister (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_sndbye (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_sndbye (id=%i)\r\n", + tr->transactionid)); +} + +static void +cb_sndcancel (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndcancel (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_sndinfo (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_sndinfo (id=%i)\r\n", + tr->transactionid)); +} + +static void +cb_sndoptions (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndoptions (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_sndnotify (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndnotify (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_sndsubscribe (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndsubscibe (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_sndunkrequest (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndunkrequest (id=%i)\r\n", tr->transactionid)); +} + +void +__eXosip_delete_jinfo (osip_transaction_t * transaction) +{ + jinfo_t *ji; + + if (transaction == NULL) + return; + ji = osip_transaction_get_your_instance (transaction); + osip_free (ji); + osip_transaction_set_your_instance (transaction, NULL); +} + +jinfo_t * +__eXosip_new_jinfo (eXosip_call_t * jc, eXosip_dialog_t * jd, + eXosip_subscribe_t * js, eXosip_notify_t * jn) +{ + jinfo_t *ji = (jinfo_t *) osip_malloc (sizeof (jinfo_t)); + + if (ji == NULL) + return NULL; + ji->jd = jd; + ji->jc = jc; + ji->js = js; + ji->jn = jn; + return ji; +} + +static void +cb_rcv1xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcv1xx (id=%i)\r\n", + tr->transactionid)); + + if (eXosip.learn_port>0) + { + struct eXosip_net *net; + net = &eXosip.net_interfaces[0]; + /* EXOSIP_OPT_UDP_LEARN_PORT option set */ +#if 1 + /* learn through rport */ + if (net->net_firewall_ip[0]!='\0') + { + osip_via_t *via=NULL; + osip_generic_param_t *br; + int i = osip_message_get_via (sip, 0, &via); + if (via!=NULL && via->protocol!=NULL + && osip_strcasecmp(via->protocol, "udp")==0) + { + osip_via_param_get_byname (via, "rport", &br); + if (br!=NULL && br->gvalue!=NULL) + { + snprintf(net->net_port, 20, "%s", br->gvalue); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcv1xx (id=%i) SIP port modified from rport in REGISTER answer\r\n", + tr->transactionid)); + } + } + } +#else + /* learn through REGISTER? */ + if (net->net_firewall_ip[0]!='\0') + { + int pos=0; + while (!osip_list_eol(reg->contacts,pos)) + { + osip_contact_t *co; + co = (osip_contact_t *)osip_list_get(reg->contacts,pos); + pos++; + if (co!=NULL && co->url!=NULL && co->url->host!=NULL + && 0==osip_strcasecmp(co->url->host, + net->net_firewall_ip)) + { + if (co->url->port==NULL && + 0!=osip_strcasecmp(net->net_port, "5060")) + { + co->url->port=osip_strdup(net->net_port); + } + else if (co->url->port!=NULL && + 0!=osip_strcasecmp(net->net_port, co->url->port)) + { + osip_free(co->url->port); + co->url->port=osip_strdup(net->net_port); + } + } + } + } +#endif + } + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR (sip, "OPTIONS")) + { + if (jc == NULL) + { + eXosip_event_t *je; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcv1xx (id=%i) OPTIONS outside of any call\r\n", + tr->transactionid)); + + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_PROCEEDING, tr); + eXosip_event_add (je); + return; + } + report_call_event (EXOSIP_CALL_MESSAGE_PROCEEDING, jc, jd, tr); + return; + } + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") && MSG_TEST_CODE (sip, 100)) + { + report_call_event (EXOSIP_CALL_PROCEEDING, jc, jd, tr); + } + + if ((MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) && !MSG_TEST_CODE (sip, 100)) + { + int i; + + /* for SUBSCRIBE, test if the dialog has been already created + with a previous NOTIFY */ + if (jd == NULL && js != NULL && js->s_dialogs != NULL + && MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + /* find if existing dialog match the to tag */ + osip_generic_param_t *tag; + int i; + + i = osip_to_get_tag (sip->to, &tag); + if (i == 0 && tag != NULL && tag->gvalue != NULL) + { + for (jd = js->s_dialogs; jd != NULL; jd = jd->next) + { + if (0 == strcmp (jd->d_dialog->remote_tag, tag->gvalue)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: found established early dialog for this subscribe\n")); + jinfo->jd = jd; + break; + } + } + } + } + + if (jd == NULL) /* This transaction initiate a dialog in the case of + INVITE (else it would be attached to a "jd" element. */ + { + /* allocate a jd */ + + i = eXosip_dialog_init_as_uac (&jd, sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot establish a dialog\n")); + return; + } + if (jc != NULL) + { + ADD_ELEMENT (jc->c_dialogs, jd); + jinfo->jd = jd; + eXosip_update (); + } else if (js != NULL) + { + ADD_ELEMENT (js->s_dialogs, jd); + jinfo->jd = jd; + eXosip_update (); + } else if (jn != NULL) + { + ADD_ELEMENT (jn->n_dialogs, jd); + jinfo->jd = jd; + eXosip_update (); + } else + { +#ifndef WIN32 + assert (0 == 0); +#else + exit (0); +#endif + } + osip_transaction_set_your_instance (tr, jinfo); + } else + { + osip_dialog_update_route_set_as_uac (jd->d_dialog, sip); + } + + if (jd != NULL) + jd->d_STATE = JD_TRYING; + if (jd != NULL && MSG_IS_RESPONSE_FOR (sip, "INVITE") + && sip->status_code < 180) + { + report_call_event (EXOSIP_CALL_PROCEEDING, jc, jd, tr); + } else if (jd != NULL && MSG_IS_RESPONSE_FOR (sip, "INVITE") + && sip->status_code >= 180) + { + report_call_event (EXOSIP_CALL_RINGING, jc, jd, tr); + } else if (jd != NULL && MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + + je = + eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_PROCEEDING, + js, jd, tr); + report_event (je, sip); + } + if (MSG_TEST_CODE (sip, 180) && jd != NULL) + { + jd->d_STATE = JD_RINGING; + } else if (MSG_TEST_CODE (sip, 183) && jd != NULL) + { + jd->d_STATE = JD_QUEUED; + } + + } +} + +static void +cb_rcv2xx_4invite (osip_transaction_t * tr, osip_message_t * sip) +{ + int i; + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd == NULL) /* This transaction initiate a dialog in the case of + INVITE (else it would be attached to a "jd" element. */ + { + /* allocate a jd */ + i = eXosip_dialog_init_as_uac (&jd, sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot establish a dialog\n")); + return; + } + ADD_ELEMENT (jc->c_dialogs, jd); + jinfo->jd = jd; + eXosip_update (); + osip_transaction_set_your_instance (tr, jinfo); + } else + { + /* Here is a special case: + We have initiated a dialog and we have received informationnal + answers from 2 or more remote SIP UA. Those answer can be + differentiated with the "To" header's tag. + + We have used the first informationnal answer to create a + dialog, but we now want to be sure the 200ok received is + for the dialog this dialog. + + We have to check the To tag and if it does not match, we + just have to modify the existing dialog and replace it. */ + osip_generic_param_t *tag; + int i; + + i = osip_to_get_tag (sip->to, &tag); + i = 1; /* default is the same dialog */ + + if (jd->d_dialog == NULL || jd->d_dialog->remote_tag == NULL) + { + /* There are real use-case where a BYE is received/processed before + the 200ok of the previous INVITE. In this case, jd->d_dialog is + empty and the transaction should be silently discarded. */ + /* a ACK should still be sent... -but there is no dialog built- */ + return; + } + + if (jd->d_dialog->remote_tag == NULL && tag == NULL) + { + } /* non compliant remote UA -> assume it is the same dialog */ + else if (jd->d_dialog->remote_tag != NULL && tag == NULL) + { + i = 0; + } /* different dialog! */ + else if (jd->d_dialog->remote_tag == NULL && tag != NULL) + { + i = 0; + } /* different dialog! */ + else if (jd->d_dialog->remote_tag != NULL && tag != NULL + && tag->gvalue != NULL + && 0 != strcmp (jd->d_dialog->remote_tag, tag->gvalue)) + { + i = 0; + } + /* different dialog! */ + if (i == 1) /* just update the dialog */ + { + osip_dialog_update_route_set_as_uac (jd->d_dialog, sip); + osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED); + } else + { + /* the best thing is to update the repace the current dialog + information... Much easier than creating a useless dialog! */ + osip_dialog_free (jd->d_dialog); + i = osip_dialog_init_as_uac (&(jd->d_dialog), sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Cannot replace the dialog.\r\n")); + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_WARNING, NULL, + "The dialog has been replaced with the new one fro 200ok.\r\n")); + } + } + } + + jd->d_STATE = JD_ESTABLISHED; + + eXosip_dialog_set_200ok (jd, sip); + + report_call_event (EXOSIP_CALL_ANSWERED, jc, jd, tr); + + /* look for the SDP information and decide if this answer was for + an initial INVITE, an HoldCall, or a RetreiveCall */ + + /* don't handle hold/unhold by now... */ + /* eXosip_update_audio_session(tr); */ + +} + +static void +cb_rcv2xx_4subscribe (osip_transaction_t * tr, osip_message_t * sip) +{ + int i; + eXosip_dialog_t *jd; + eXosip_subscribe_t *js; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + if (jinfo == NULL) + return; + jd = jinfo->jd; + js = jinfo->js; + _eXosip_subscribe_set_refresh_interval (js, sip); + + + /* for SUBSCRIBE, test if the dialog has been already created + with a previous NOTIFY */ + if (jd == NULL && js != NULL && js->s_dialogs != NULL + && MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + /* find if existing dialog match the to tag */ + osip_generic_param_t *tag; + int i; + + i = osip_to_get_tag (sip->to, &tag); + if (i == 0 && tag != NULL && tag->gvalue != NULL) + { + for (jd = js->s_dialogs; jd != NULL; jd = jd->next) + { + if (0 == strcmp (jd->d_dialog->remote_tag, tag->gvalue)) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: found established early dialog for this subscribe\n")); + jinfo->jd = jd; + break; + } + } + } + } + + if (jd == NULL) /* This transaction initiate a dialog in the case of + SUBSCRIBE (else it would be attached to a "jd" element. */ + { + /* allocate a jd */ + i = eXosip_dialog_init_as_uac (&jd, sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot establish a dialog\n")); + return; + } + ADD_ELEMENT (js->s_dialogs, jd); + jinfo->jd = jd; + eXosip_update (); + osip_transaction_set_your_instance (tr, jinfo); + } else + { + osip_dialog_update_route_set_as_uac (jd->d_dialog, sip); + osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED); + } + + jd->d_STATE = JD_ESTABLISHED; + /* look for the body information */ + + { + eXosip_event_t *je; + + je = + eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_ANSWERED, js, jd, tr); + report_event (je, sip); + } + +} + +static void +cb_rcv2xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcv2xx (id=%i)\r\n", + tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR (sip, "PUBLISH")) + { + eXosip_pub_t *pub; + eXosip_event_t *je; + int i; + + i = _eXosip_pub_update (&pub, tr, sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "cb_rcv2xx (id=%i) No publication to update\r\n", + tr->transactionid)); + } + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_ANSWERED, tr); + report_event (je, sip); + return; + } else if (MSG_IS_RESPONSE_FOR (sip, "REGISTER")) + { + eXosip_event_t *je; + eXosip_reg_t *jreg = NULL; + + /* find matching j_reg */ + _eXosip_reg_find (&jreg, tr); + if (jreg != NULL) + { + je = eXosip_event_init_for_reg (EXOSIP_REGISTRATION_SUCCESS, jreg, tr); + report_event (je, sip); + jreg->r_retry = 0; /* reset value */ + } + + + if (eXosip.learn_port>0) + { + struct eXosip_net *net; + net = &eXosip.net_interfaces[0]; + /* EXOSIP_OPT_UDP_LEARN_PORT option set */ +#if 1 + /* learn through rport */ + if (net->net_firewall_ip[0]!='\0') + { + osip_via_t *via=NULL; + osip_generic_param_t *br; + int i = osip_message_get_via (sip, 0, &via); + if (via!=NULL && via->protocol!=NULL + && osip_strcasecmp(via->protocol, "udp")==0) + { + osip_via_param_get_byname (via, "rport", &br); + if (br!=NULL && br->gvalue!=NULL) + { + snprintf(net->net_port, 20, "%s", br->gvalue); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcv1xx (id=%i) SIP port modified from rport in REGISTER answer\r\n", + tr->transactionid)); + } + } + } +#else + /* learn through REGISTER? */ + if (net->net_firewall_ip[0]!='\0') + { + int pos=0; + while (!osip_list_eol(reg->contacts,pos)) + { + osip_contact_t *co; + co = (osip_contact_t *)osip_list_get(reg->contacts,pos); + pos++; + if (co!=NULL && co->url!=NULL && co->url->host!=NULL + && 0==osip_strcasecmp(co->url->host, + net->net_firewall_ip)) + { + if (co->url->port==NULL && + 0!=osip_strcasecmp(net->net_port, "5060")) + { + co->url->port=osip_strdup(net->net_port); + } + else if (co->url->port!=NULL && + 0!=osip_strcasecmp(net->net_port, co->url->port)) + { + osip_free(co->url->port); + co->url->port=osip_strdup(net->net_port); + } + } + } + } +#endif + } + + return; + } + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (jd != NULL) + jd->d_retry = 0; /* reset marker for authentication */ + if (jc != NULL) + jc->c_retry = 0; /* reset marker for authentication */ + if (js != NULL) + js->s_retry = 0; /* reset marker for authentication */ + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + cb_rcv2xx_4invite (tr, sip); + } else if (MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + cb_rcv2xx_4subscribe (tr, sip); + } else if (MSG_IS_RESPONSE_FOR (sip, "BYE")) + { + if (jd != NULL) + jd->d_STATE = JD_TERMINATED; + } else if (MSG_IS_RESPONSE_FOR (sip, "NOTIFY")) + { +#ifdef SUPPORT_MSN + osip_header_t *expires; + + osip_message_header_get_byname (tr->orig_request, "expires", 0, &expires); + if (expires == NULL || expires->hvalue == NULL) + { + /* UNCOMPLIANT UA without a subscription-state header */ + } else if (0 == osip_strcasecmp (expires->hvalue, "0")) + { + /* delete the dialog! */ + if (jn != NULL) + { + REMOVE_ELEMENT (eXosip.j_notifies, jn); + eXosip_notify_free (jn); + } + } +#else + osip_header_t *sub_state; + + osip_message_header_get_byname (tr->orig_request, "subscription-state", + 0, &sub_state); + if (sub_state == NULL || sub_state->hvalue == NULL) + { + /* UNCOMPLIANT UA without a subscription-state header */ + } else if (0 == osip_strncasecmp (sub_state->hvalue, "terminated", 10)) + { + /* delete the dialog! */ + if (jn != NULL) + { + REMOVE_ELEMENT (eXosip.j_notifies, jn); + eXosip_notify_free (jn); + } + } +#endif + } else if (jc!=NULL) + { + report_call_event (EXOSIP_CALL_MESSAGE_ANSWERED, jc, jd, tr); + return; + } else if (jc==NULL && js==NULL && jn==NULL) + { + eXosip_event_t *je; + /* For all requests outside of calls */ + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_ANSWERED, tr); + report_event (je, sip); + return; + } +} + +void +eXosip_delete_early_dialog (eXosip_dialog_t * jd) +{ + if (jd == NULL) /* bug? */ + return; + + /* an early dialog was created, but the call is not established */ + if (jd->d_dialog != NULL && jd->d_dialog->state == DIALOG_EARLY) + { + osip_dialog_free (jd->d_dialog); + jd->d_dialog = NULL; + eXosip_update(); //AMD 30/09/05 + eXosip_dialog_set_state (jd, JD_TERMINATED); + } +} + +static void +rcvregister_failure (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_event_t *je; + eXosip_reg_t *jreg = NULL; + + /* find matching j_reg */ + _eXosip_reg_find (&jreg, tr); + if (jreg != NULL) + { + je = eXosip_event_init_for_reg (EXOSIP_REGISTRATION_FAILURE, jreg, tr); + report_event (je, sip); + } +} + +static void +cb_rcv3xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcv3xx (id=%i)\r\n", + tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR (sip, "PUBLISH")) + { + eXosip_event_t *je; + eXosip_pub_t *pub; + int i; + + i = _eXosip_pub_update (&pub, tr, sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "cb_rcv3xx (id=%i) No publication to update\r\n", + tr->transactionid)); + } + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_REDIRECTED, tr); + report_event (je, sip); + return; + } else if (MSG_IS_RESPONSE_FOR (sip, "REGISTER")) + { + rcvregister_failure (type, tr, sip); + return; + } + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + report_call_event (EXOSIP_CALL_REDIRECTED, jc, jd, tr); + } else if (MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + + je = + eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_REDIRECTED, js, + jd, tr); + report_event (je, sip); + } else if (jc!=NULL) + { + report_call_event (EXOSIP_CALL_MESSAGE_REDIRECTED, jc, jd, tr); + return; + } else if (jc==NULL && js==NULL && jn==NULL) + { + eXosip_event_t *je; + /* For all requests outside of calls */ + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_REDIRECTED, tr); + report_event (je, sip); + return; + } + + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog (jd); + if (jd->d_dialog == NULL) + jd->d_STATE = JD_REDIRECTED; + } + +} + +static void +cb_rcv4xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcv4xx (id=%i)\r\n", + tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR (sip, "PUBLISH")) + { + eXosip_pub_t *pub; + eXosip_event_t *je; + int i; + + i = _eXosip_pub_update (&pub, tr, sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "cb_rcv4xx (id=%i) No publication to update\r\n", + tr->transactionid)); + } + /* For all requests outside of calls */ + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_REQUESTFAILURE, tr); + report_event (je, sip); + return; + } else if (MSG_IS_RESPONSE_FOR (sip, "REGISTER")) + { + rcvregister_failure (type, tr, sip); + return; + } + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + report_call_event (EXOSIP_CALL_REQUESTFAILURE, jc, jd, tr); + } else if (MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + + je = + eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_REQUESTFAILURE, + js, jd, tr); + report_event (je, sip); + } else if (jc!=NULL) + { + report_call_event (EXOSIP_CALL_MESSAGE_REQUESTFAILURE, jc, jd, tr); + return; + } else if (jc==NULL && js==NULL && jn==NULL) + { + eXosip_event_t *je; + /* For all requests outside of calls */ + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_REQUESTFAILURE, tr); + report_event (je, sip); + return; + } + + if (jc!=NULL) + { + if (MSG_TEST_CODE (sip, 401) || MSG_TEST_CODE (sip, 407)) + { + if (jc->response_auth!=NULL) + osip_message_free(jc->response_auth); + + osip_message_clone(sip, &jc->response_auth); + } + } + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog (jd); + if (MSG_TEST_CODE (sip, 401) || MSG_TEST_CODE (sip, 407)) + jd->d_STATE = JD_AUTH_REQUIRED; + else + jd->d_STATE = JD_CLIENTERROR; + } + +} + +static void +cb_rcv5xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcv5xx (id=%i)\r\n", + tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR (sip, "PUBLISH")) + { + eXosip_pub_t *pub; + eXosip_event_t *je; + int i; + + i = _eXosip_pub_update (&pub, tr, sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "cb_rcv3xx (id=%i) No publication to update\r\n", + tr->transactionid)); + } + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_SERVERFAILURE, tr); + report_event (je, sip); + return; + } else if (MSG_IS_RESPONSE_FOR (sip, "REGISTER")) + { + rcvregister_failure (type, tr, sip); + return; + } + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + report_call_event (EXOSIP_CALL_SERVERFAILURE, jc, jd, tr); + } else if (MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + + je = + eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_SERVERFAILURE, + js, jd, tr); + report_event (je, sip); + } else if (jc!=NULL) + { + report_call_event (EXOSIP_CALL_MESSAGE_SERVERFAILURE, jc, jd, tr); + return; + } else if (jc==NULL && js==NULL && jn==NULL) + { + eXosip_event_t *je; + /* For all requests outside of calls */ + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_SERVERFAILURE, tr); + report_event (je, sip); + return; + } + + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog (jd); + jd->d_STATE = JD_SERVERERROR; + } + +} + +static void +cb_rcv6xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_rcv6xx (id=%i)\r\n", + tr->transactionid)); + + if (MSG_IS_RESPONSE_FOR (sip, "PUBLISH")) + { + eXosip_pub_t *pub; + eXosip_event_t *je; + int i; + + i = _eXosip_pub_update (&pub, tr, sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "cb_rcv6xx (id=%i) No publication to update\r\n", + tr->transactionid)); + } + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_GLOBALFAILURE, tr); + report_event (je, sip); + return; + } else if (MSG_IS_RESPONSE_FOR (sip, "REGISTER")) + { + rcvregister_failure (type, tr, sip); + return; + } + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + report_call_event (EXOSIP_CALL_GLOBALFAILURE, jc, jd, tr); + } else if (MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_event_t *je; + + je = + eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_GLOBALFAILURE, + js, jd, tr); + report_event (je, sip); + } else if (jc!=NULL) + { + report_call_event (EXOSIP_CALL_MESSAGE_GLOBALFAILURE, jc, jd, tr); + return; + } else if (jc==NULL && js==NULL && jn==NULL) + { + eXosip_event_t *je; + /* For all requests outside of calls */ + je = eXosip_event_init_for_message (EXOSIP_MESSAGE_GLOBALFAILURE, tr); + report_event (je, sip); + return; + } + + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog (jd); + jd->d_STATE = JD_GLOBALFAILURE; + } + +} + +static void +cb_snd1xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_snd1xx (id=%i)\r\n", + tr->transactionid)); + + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd == NULL) + return; + jd->d_STATE = JD_TRYING; +} + +static void +cb_snd2xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_snd2xx (id=%i)\r\n", + tr->transactionid)); + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + jd->d_STATE = JD_ESTABLISHED; + return; + } + jd->d_STATE = JD_ESTABLISHED; +} + +static void +cb_snd3xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_snd3xx (id=%i)\r\n", + tr->transactionid)); + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog (jd); + } + jd->d_STATE = JD_REDIRECTED; + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + /* only close calls if this is the initial INVITE */ + if (jc!=NULL && tr == jc->c_inc_tr) + { + report_call_event (EXOSIP_CALL_CLOSED, jc, jd, tr); + } + } +} + +static void +cb_snd4xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_snd4xx (id=%i)\r\n", + tr->transactionid)); + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog (jd); + } + jd->d_STATE = JD_CLIENTERROR; + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + /* only close calls if this is the initial INVITE */ + if (jc!=NULL && tr == jc->c_inc_tr) + { + report_call_event (EXOSIP_CALL_CLOSED, jc, jd, tr); + } + } + +} + +static void +cb_snd5xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_snd5xx (id=%i)\r\n", + tr->transactionid)); + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog (jd); + } + jd->d_STATE = JD_SERVERERROR; + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + /* only close calls if this is the initial INVITE */ + if (jc!=NULL && tr == jc->c_inc_tr) + { + report_call_event (EXOSIP_CALL_CLOSED, jc, jd, tr); + } + } + +} + +static void +cb_snd6xx (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, "cb_snd6xx (id=%i)\r\n", + tr->transactionid)); + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + if (jd == NULL) + return; + if (MSG_IS_RESPONSE_FOR (sip, "INVITE") + || MSG_IS_RESPONSE_FOR (sip, "SUBSCRIBE")) + { + eXosip_delete_early_dialog (jd); + } + jd->d_STATE = JD_GLOBALFAILURE; + + if (MSG_IS_RESPONSE_FOR (sip, "INVITE")) + { + /* only close calls if this is the initial INVITE */ + if (jc!=NULL && tr == jc->c_inc_tr) + { + report_call_event (EXOSIP_CALL_CLOSED, jc, jd, tr); + } + } + +} + +static void +cb_rcvresp_retransmission (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcvresp_retransmission (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_sndreq_retransmission (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndreq_retransmission (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_sndresp_retransmission (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_sndresp_retransmission (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_rcvreq_retransmission (int type, osip_transaction_t * tr, osip_message_t * sip) +{ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_rcvreq_retransmission (id=%i)\r\n", tr->transactionid)); +} + +static void +cb_transport_error (int type, osip_transaction_t * tr, int error) +{ + eXosip_dialog_t *jd; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + jinfo_t *jinfo = (jinfo_t *) osip_transaction_get_your_instance (tr); + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "cb_transport_error (id=%i)\r\n", tr->transactionid)); + if (jinfo == NULL) + return; + jd = jinfo->jd; + jc = jinfo->jc; + jn = jinfo->jn; + js = jinfo->js; + + if (jn == NULL && js == NULL) + return; + + if (MSG_IS_NOTIFY (tr->orig_request) && type == OSIP_NICT_TRANSPORT_ERROR) + { + /* delete the dialog! */ + REMOVE_ELEMENT (eXosip.j_notifies, jn); + eXosip_notify_free (jn); + } + + if (MSG_IS_SUBSCRIBE (tr->orig_request) && type == OSIP_NICT_TRANSPORT_ERROR) + { + /* delete the dialog! */ + REMOVE_ELEMENT (eXosip.j_subscribes, js); + eXosip_subscribe_free (js); + } + + if (MSG_IS_OPTIONS (tr->orig_request) && jc->c_dialogs == NULL + && type == OSIP_NICT_TRANSPORT_ERROR) + { + /* delete the dialog! */ + REMOVE_ELEMENT (eXosip.j_calls, jc); + eXosip_call_free (jc); + } +} + + + +int +eXosip_set_callbacks (osip_t * osip) +{ + /* register all callbacks */ + + osip_set_cb_send_message (osip, &cb_snd_message); + + osip_set_kill_transaction_callback (osip, OSIP_ICT_KILL_TRANSACTION, + &cb_ict_kill_transaction); + osip_set_kill_transaction_callback (osip, OSIP_IST_KILL_TRANSACTION, + &cb_ist_kill_transaction); + osip_set_kill_transaction_callback (osip, OSIP_NICT_KILL_TRANSACTION, + &cb_nict_kill_transaction); + osip_set_kill_transaction_callback (osip, OSIP_NIST_KILL_TRANSACTION, + &cb_nist_kill_transaction); + + osip_set_message_callback (osip, OSIP_ICT_STATUS_2XX_RECEIVED_AGAIN, + &cb_rcvresp_retransmission); + osip_set_message_callback (osip, OSIP_ICT_STATUS_3456XX_RECEIVED_AGAIN, + &cb_rcvresp_retransmission); + osip_set_message_callback (osip, OSIP_ICT_INVITE_SENT_AGAIN, + &cb_sndreq_retransmission); + osip_set_message_callback (osip, OSIP_IST_STATUS_2XX_SENT_AGAIN, + &cb_sndresp_retransmission); + osip_set_message_callback (osip, OSIP_IST_STATUS_3456XX_SENT_AGAIN, + &cb_sndresp_retransmission); + osip_set_message_callback (osip, OSIP_IST_INVITE_RECEIVED_AGAIN, + &cb_rcvreq_retransmission); + osip_set_message_callback (osip, OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN, + &cb_rcvresp_retransmission); + osip_set_message_callback (osip, OSIP_NICT_STATUS_3456XX_RECEIVED_AGAIN, + &cb_rcvresp_retransmission); + osip_set_message_callback (osip, OSIP_NICT_REQUEST_SENT_AGAIN, + &cb_sndreq_retransmission); + osip_set_message_callback (osip, OSIP_NIST_STATUS_2XX_SENT_AGAIN, + &cb_sndresp_retransmission); + osip_set_message_callback (osip, OSIP_NIST_STATUS_3456XX_SENT_AGAIN, + &cb_sndresp_retransmission); + osip_set_message_callback (osip, OSIP_NIST_REQUEST_RECEIVED_AGAIN, + &cb_rcvreq_retransmission); + + osip_set_transport_error_callback (osip, OSIP_ICT_TRANSPORT_ERROR, + &cb_transport_error); + osip_set_transport_error_callback (osip, OSIP_IST_TRANSPORT_ERROR, + &cb_transport_error); + osip_set_transport_error_callback (osip, OSIP_NICT_TRANSPORT_ERROR, + &cb_transport_error); + osip_set_transport_error_callback (osip, OSIP_NIST_TRANSPORT_ERROR, + &cb_transport_error); + + osip_set_message_callback (osip, OSIP_ICT_INVITE_SENT, &cb_sndinvite); + osip_set_message_callback (osip, OSIP_ICT_ACK_SENT, &cb_sndack); + osip_set_message_callback (osip, OSIP_NICT_REGISTER_SENT, &cb_sndregister); + osip_set_message_callback (osip, OSIP_NICT_BYE_SENT, &cb_sndbye); + osip_set_message_callback (osip, OSIP_NICT_CANCEL_SENT, &cb_sndcancel); + osip_set_message_callback (osip, OSIP_NICT_INFO_SENT, &cb_sndinfo); + osip_set_message_callback (osip, OSIP_NICT_OPTIONS_SENT, &cb_sndoptions); + osip_set_message_callback (osip, OSIP_NICT_SUBSCRIBE_SENT, &cb_sndsubscribe); + osip_set_message_callback (osip, OSIP_NICT_NOTIFY_SENT, &cb_sndnotify); + /* osip_set_cb_nict_sndprack (osip,&cb_sndprack); */ + osip_set_message_callback (osip, OSIP_NICT_UNKNOWN_REQUEST_SENT, + &cb_sndunkrequest); + + osip_set_message_callback (osip, OSIP_ICT_STATUS_1XX_RECEIVED, &cb_rcv1xx); + osip_set_message_callback (osip, OSIP_ICT_STATUS_2XX_RECEIVED, &cb_rcv2xx); + osip_set_message_callback (osip, OSIP_ICT_STATUS_3XX_RECEIVED, &cb_rcv3xx); + osip_set_message_callback (osip, OSIP_ICT_STATUS_4XX_RECEIVED, &cb_rcv4xx); + osip_set_message_callback (osip, OSIP_ICT_STATUS_5XX_RECEIVED, &cb_rcv5xx); + osip_set_message_callback (osip, OSIP_ICT_STATUS_6XX_RECEIVED, &cb_rcv6xx); + + osip_set_message_callback (osip, OSIP_IST_STATUS_1XX_SENT, &cb_snd1xx); + osip_set_message_callback (osip, OSIP_IST_STATUS_2XX_SENT, &cb_snd2xx); + osip_set_message_callback (osip, OSIP_IST_STATUS_3XX_SENT, &cb_snd3xx); + osip_set_message_callback (osip, OSIP_IST_STATUS_4XX_SENT, &cb_snd4xx); + osip_set_message_callback (osip, OSIP_IST_STATUS_5XX_SENT, &cb_snd5xx); + osip_set_message_callback (osip, OSIP_IST_STATUS_6XX_SENT, &cb_snd6xx); + + osip_set_message_callback (osip, OSIP_NICT_STATUS_1XX_RECEIVED, &cb_rcv1xx); + osip_set_message_callback (osip, OSIP_NICT_STATUS_2XX_RECEIVED, &cb_rcv2xx); + osip_set_message_callback (osip, OSIP_NICT_STATUS_3XX_RECEIVED, &cb_rcv3xx); + osip_set_message_callback (osip, OSIP_NICT_STATUS_4XX_RECEIVED, &cb_rcv4xx); + osip_set_message_callback (osip, OSIP_NICT_STATUS_5XX_RECEIVED, &cb_rcv5xx); + osip_set_message_callback (osip, OSIP_NICT_STATUS_6XX_RECEIVED, &cb_rcv6xx); + + osip_set_message_callback (osip, OSIP_NIST_STATUS_1XX_SENT, &cb_snd1xx); + osip_set_message_callback (osip, OSIP_NIST_STATUS_2XX_SENT, &cb_snd2xx); + osip_set_message_callback (osip, OSIP_NIST_STATUS_3XX_SENT, &cb_snd3xx); + osip_set_message_callback (osip, OSIP_NIST_STATUS_4XX_SENT, &cb_snd4xx); + osip_set_message_callback (osip, OSIP_NIST_STATUS_5XX_SENT, &cb_snd5xx); + osip_set_message_callback (osip, OSIP_NIST_STATUS_6XX_SENT, &cb_snd6xx); + + osip_set_message_callback (osip, OSIP_IST_INVITE_RECEIVED, &cb_rcvinvite); + osip_set_message_callback (osip, OSIP_IST_ACK_RECEIVED, &cb_rcvack); + osip_set_message_callback (osip, OSIP_IST_ACK_RECEIVED_AGAIN, &cb_rcvack2); + osip_set_message_callback (osip, OSIP_NIST_REGISTER_RECEIVED, &cb_rcvregister); + osip_set_message_callback (osip, OSIP_NIST_CANCEL_RECEIVED, &cb_rcvcancel); + osip_set_message_callback (osip, OSIP_NIST_BYE_RECEIVED, &cb_rcvrequest); + osip_set_message_callback (osip, OSIP_NIST_INFO_RECEIVED, &cb_rcvrequest); + osip_set_message_callback (osip, OSIP_NIST_OPTIONS_RECEIVED, &cb_rcvrequest); + osip_set_message_callback (osip, OSIP_NIST_SUBSCRIBE_RECEIVED, &cb_rcvrequest); + osip_set_message_callback (osip, OSIP_NIST_NOTIFY_RECEIVED, &cb_rcvrequest); + osip_set_message_callback (osip, OSIP_NIST_UNKNOWN_REQUEST_RECEIVED, + &cb_rcvrequest); + + return 0; +} diff --git a/exosip2/jdialog.c b/exosip2/jdialog.c new file mode 100644 index 0000000000000000000000000000000000000000..d8010252cb17b7816092d41ff4fc477f0157c6c0 --- /dev/null +++ b/exosip2/jdialog.c @@ -0,0 +1,217 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +void +eXosip_dialog_set_state (eXosip_dialog_t * jd, int state) +{ + jd->d_STATE = state; +} + + +int +eXosip_call_dialog_find (int jid, eXosip_call_t ** jc, eXosip_dialog_t ** jd) +{ + for (*jc = eXosip.j_calls; *jc != NULL; *jc = (*jc)->next) + { + for (*jd = (*jc)->c_dialogs; *jd != NULL; *jd = (*jd)->next) + { + if ((*jd)->d_id == jid) + return 0; + } + } + *jd = NULL; + *jc = NULL; + return -1; +} + +int +eXosip_notify_dialog_find (int nid, eXosip_notify_t ** jn, eXosip_dialog_t ** jd) +{ + for (*jn = eXosip.j_notifies; *jn != NULL; *jn = (*jn)->next) + { + for (*jd = (*jn)->n_dialogs; *jd != NULL; *jd = (*jd)->next) + { + if ((*jd)->d_id == nid) + return 0; + } + } + *jd = NULL; + *jn = NULL; + return -1; +} + +int +eXosip_subscribe_dialog_find (int sid, eXosip_subscribe_t ** js, + eXosip_dialog_t ** jd) +{ + for (*js = eXosip.j_subscribes; *js != NULL; *js = (*js)->next) + { + *jd = NULL; + if ((*js)->s_id == sid) + return 0; + for (*jd = (*js)->s_dialogs; *jd != NULL; *jd = (*jd)->next) + { + if ((*jd)->d_id == sid) + return 0; + } + } + *jd = NULL; + *js = NULL; + return -1; +} + +int +eXosip_dialog_set_200ok (eXosip_dialog_t * jd, osip_message_t * _200Ok) +{ + int i; + + if (jd == NULL) + return -1; + i = osip_message_clone (_200Ok, &(jd->d_200Ok)); + if (i != 0) + { + return -1; + } + return 0; +} + +int +eXosip_dialog_init_as_uac (eXosip_dialog_t ** _jd, osip_message_t * _200Ok) +{ + int i; + eXosip_dialog_t *jd; + + *_jd = NULL; + jd = (eXosip_dialog_t *) osip_malloc (sizeof (eXosip_dialog_t)); + memset (jd, 0, sizeof (eXosip_dialog_t)); + + jd->d_id = -1; /* not yet available to user */ + jd->d_STATE = JD_EMPTY; + + if (MSG_IS_REQUEST (_200Ok)) + { + i = + osip_dialog_init_as_uac_with_remote_request (&(jd->d_dialog), _200Ok, -1); + } else + { /* normal usage with response */ + i = osip_dialog_init_as_uac (&(jd->d_dialog), _200Ok); + } + if (i != 0) + { + osip_free (jd); + return -1; + } + + jd->d_timer = time (NULL); + jd->d_200Ok = NULL; + jd->d_ack = NULL; + jd->next = NULL; + jd->parent = NULL; + jd->d_out_trs = (osip_list_t *) osip_malloc (sizeof (osip_list_t)); + osip_list_init (jd->d_out_trs); + jd->d_inc_trs = (osip_list_t *) osip_malloc (sizeof (osip_list_t)); + osip_list_init (jd->d_inc_trs); + + /* jd->d_bh = sdp_handler_new(); */ + *_jd = jd; + return 0; +} + +int +eXosip_dialog_init_as_uas (eXosip_dialog_t ** _jd, osip_message_t * _invite, + osip_message_t * _200Ok) +{ + int i; + eXosip_dialog_t *jd; + + *_jd = NULL; + jd = (eXosip_dialog_t *) osip_malloc (sizeof (eXosip_dialog_t)); + memset (jd, 0, sizeof (eXosip_dialog_t)); + jd->d_id = -1; /* not yet available to user */ + jd->d_STATE = JD_EMPTY; + i = osip_dialog_init_as_uas (&(jd->d_dialog), _invite, _200Ok); + if (i != 0) + { + osip_free (jd); + return -1; + } + + jd->d_timer = time (NULL); + jd->d_200Ok = NULL; + jd->d_ack = NULL; + jd->next = NULL; + jd->parent = NULL; + jd->d_out_trs = (osip_list_t *) osip_malloc (sizeof (osip_list_t)); + osip_list_init (jd->d_out_trs); + jd->d_inc_trs = (osip_list_t *) osip_malloc (sizeof (osip_list_t)); + osip_list_init (jd->d_inc_trs); + +#ifdef SUPPORT_MSN + /* bugguy MSN */ + jd->d_dialog->local_cseq = 1; +#endif + + /* jd->d_bh = sdp_handler_new(); */ + *_jd = jd; + return 0; +} + +void +eXosip_dialog_free (eXosip_dialog_t * jd) +{ + while (!osip_list_eol (jd->d_inc_trs, 0)) + { + osip_transaction_t *tr; + + tr = (osip_transaction_t *) osip_list_get (jd->d_inc_trs, 0); + osip_list_remove (jd->d_inc_trs, 0); + __eXosip_delete_jinfo (tr); + osip_list_add (eXosip.j_transactions, tr, 0); + } + + while (!osip_list_eol (jd->d_out_trs, 0)) + { + osip_transaction_t *tr; + + tr = (osip_transaction_t *) osip_list_get (jd->d_out_trs, 0); + osip_list_remove (jd->d_out_trs, 0); + __eXosip_delete_jinfo (tr); + osip_list_add (eXosip.j_transactions, tr, 0); + } + + osip_message_free (jd->d_200Ok); + osip_message_free (jd->d_ack); + + osip_dialog_free (jd->d_dialog); + + osip_free (jd->d_out_trs); + osip_free (jd->d_inc_trs); + osip_free (jd); + + eXosip_update (); +} diff --git a/exosip2/jevents.c b/exosip2/jevents.c new file mode 100644 index 0000000000000000000000000000000000000000..a59092ce99047c0683612cb9650e4fc9f090f0f3 --- /dev/null +++ b/exosip2/jevents.c @@ -0,0 +1,511 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" +#include <eXosip2/eXosip.h> +#include <osip2/osip_condv.h> + +extern eXosip_t eXosip; + +static int _eXosip_event_fill_messages (eXosip_event_t * je, + osip_transaction_t * tr); + +static int +_eXosip_event_fill_messages (eXosip_event_t * je, osip_transaction_t * tr) +{ + int i; + + if (tr != NULL && tr->orig_request != NULL) + { + i = osip_message_clone (tr->orig_request, &je->request); + if (i != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "failed to clone request for event\n")); + } + } + if (tr != NULL && tr->last_response != NULL) + { + i = osip_message_clone (tr->last_response, &je->response); + if (i != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "failed to clone response for event\n")); + } + } + if (tr != NULL && tr->ack != NULL) + { + i = osip_message_clone (tr->ack, &je->ack); + if (i != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "failed to clone ACK for event\n")); + } + } + return 0; +} + +eXosip_event_t * +eXosip_event_init_for_call (int type, eXosip_call_t * jc, + eXosip_dialog_t * jd, osip_transaction_t * tr) +{ + eXosip_event_t *je; + + eXosip_event_init (&je, type); + if (je == NULL) + return NULL; + if (jc == NULL) + return NULL; + + je->cid = jc->c_id; + if (jd != NULL) + je->did = jd->d_id; + if (tr != NULL) + je->tid = tr->transactionid; + + je->external_reference = jc->external_reference; + + _eXosip_event_fill_messages (je, tr); + return je; +} + +eXosip_event_t * +eXosip_event_init_for_subscribe (int type, eXosip_subscribe_t * js, + eXosip_dialog_t * jd, osip_transaction_t * tr) +{ + eXosip_event_t *je; + + eXosip_event_init (&je, type); + if (je == NULL) + return NULL; + if (js == NULL) + return NULL; + + je->sid = js->s_id; + if (jd != NULL) + je->did = jd->d_id; + if (tr != NULL) + je->tid = tr->transactionid; + + je->ss_status = js->s_ss_status; + je->ss_reason = js->s_ss_reason; + + /* je->external_reference = js->external_reference; */ + + _eXosip_event_fill_messages (je, tr); + + return je; +} + +eXosip_event_t * +eXosip_event_init_for_notify (int type, eXosip_notify_t * jn, + eXosip_dialog_t * jd, osip_transaction_t * tr) +{ + eXosip_event_t *je; + + eXosip_event_init (&je, type); + if (je == NULL) + return NULL; + if (jn == NULL) + return NULL; + + je->nid = jn->n_id; + if (jd != NULL) + je->did = jd->d_id; + if (tr != NULL) + je->tid = tr->transactionid; + + je->ss_status = jn->n_ss_status; + je->ss_reason = jn->n_ss_reason; + + /*je->external_reference = jc->external_reference; */ + + _eXosip_event_fill_messages (je, tr); + + return je; +} + +eXosip_event_t * +eXosip_event_init_for_reg (int type, eXosip_reg_t * jr, osip_transaction_t * tr) +{ + eXosip_event_t *je; + + eXosip_event_init (&je, type); + if (je == NULL) + return NULL; + if (jr == NULL) + return NULL; + je->rid = jr->r_id; + + _eXosip_event_fill_messages (je, tr); + return je; +} + +eXosip_event_t * +eXosip_event_init_for_message (int type, osip_transaction_t * tr) +{ + eXosip_event_t *je; + + eXosip_event_init (&je, type); + if (je == NULL) + return NULL; + + if (tr != NULL) + je->tid = tr->transactionid; + + _eXosip_event_fill_messages (je, tr); + + return je; +} + +int +eXosip_event_init (eXosip_event_t ** je, int type) +{ + *je = (eXosip_event_t *) osip_malloc (sizeof (eXosip_event_t)); + if (*je == NULL) + return -1; + + memset (*je, 0, sizeof (eXosip_event_t)); + (*je)->type = type; + + if (type == EXOSIP_CALL_NOANSWER) + { + sprintf ((*je)->textinfo, "No answer for this Call!"); + } else if (type == EXOSIP_CALL_PROCEEDING) + { + sprintf ((*je)->textinfo, "Call is being processed!"); + } else if (type == EXOSIP_CALL_RINGING) + { + sprintf ((*je)->textinfo, "Remote phone is ringing!"); + } else if (type == EXOSIP_CALL_ANSWERED) + { + sprintf ((*je)->textinfo, "Remote phone has answered!"); + } else if (type == EXOSIP_CALL_REDIRECTED) + { + sprintf ((*je)->textinfo, "Call is redirected!"); + } else if (type == EXOSIP_CALL_REQUESTFAILURE) + { + sprintf ((*je)->textinfo, "4xx received for Call!"); + } else if (type == EXOSIP_CALL_SERVERFAILURE) + { + sprintf ((*je)->textinfo, "5xx received for Call!"); + } else if (type == EXOSIP_CALL_GLOBALFAILURE) + { + sprintf ((*je)->textinfo, "6xx received for Call!"); + } else if (type == EXOSIP_CALL_INVITE) + { + sprintf ((*je)->textinfo, "New call received!"); + } else if (type == EXOSIP_CALL_ACK) + { + sprintf ((*je)->textinfo, "ACK received!"); + } else if (type == EXOSIP_CALL_CANCELLED) + { + sprintf ((*je)->textinfo, "Call has been cancelled!"); + } else if (type == EXOSIP_CALL_TIMEOUT) + { + sprintf ((*je)->textinfo, "Timeout. Gave up!"); + } else if (type == EXOSIP_CALL_REINVITE) + { + sprintf ((*je)->textinfo, "INVITE within call received!"); + } else if (type == EXOSIP_CALL_CLOSED) + { + sprintf ((*je)->textinfo, "Bye Received!"); + } else if (type == EXOSIP_CALL_RELEASED) + { + sprintf ((*je)->textinfo, "Call Context is released!"); + } else if (type == EXOSIP_REGISTRATION_SUCCESS) + { + sprintf ((*je)->textinfo, "User is successfully registred!"); + } else if (type == EXOSIP_REGISTRATION_FAILURE) + { + sprintf ((*je)->textinfo, "Registration failed!"); + } else if (type == EXOSIP_CALL_MESSAGE_NEW) + { + sprintf ((*je)->textinfo, "New request received!"); + } else if (type == EXOSIP_CALL_MESSAGE_PROCEEDING) + { + sprintf ((*je)->textinfo, "request is being processed!"); + } else if (type == EXOSIP_CALL_MESSAGE_ANSWERED) + { + sprintf ((*je)->textinfo, "2xx received for request!"); + } else if (type == EXOSIP_CALL_MESSAGE_REDIRECTED) + { + sprintf ((*je)->textinfo, "3xx received for request!"); + } else if (type == EXOSIP_CALL_MESSAGE_REQUESTFAILURE) + { + sprintf ((*je)->textinfo, "4xx received for request!"); + } else if (type == EXOSIP_CALL_MESSAGE_SERVERFAILURE) + { + sprintf ((*je)->textinfo, "5xx received for request!"); + } else if (type == EXOSIP_CALL_MESSAGE_GLOBALFAILURE) + { + sprintf ((*je)->textinfo, "5xx received for request!"); + } else if (type == EXOSIP_MESSAGE_NEW) + { + sprintf ((*je)->textinfo, "New request outside call received!"); + } else if (type == EXOSIP_MESSAGE_PROCEEDING) + { + sprintf ((*je)->textinfo, "request outside call is being processed!"); + } else if (type == EXOSIP_MESSAGE_ANSWERED) + { + sprintf ((*je)->textinfo, "2xx received for request outside call!"); + } else if (type == EXOSIP_MESSAGE_REDIRECTED) + { + sprintf ((*je)->textinfo, "3xx received for request outside call!"); + } else if (type == EXOSIP_MESSAGE_REQUESTFAILURE) + { + sprintf ((*je)->textinfo, "4xx received for request outside call!"); + } else if (type == EXOSIP_MESSAGE_SERVERFAILURE) + { + sprintf ((*je)->textinfo, "5xx received for request outside call!"); + } else if (type == EXOSIP_MESSAGE_GLOBALFAILURE) + { + sprintf ((*je)->textinfo, "5xx received for request outside call!"); + } else if (type == EXOSIP_SUBSCRIPTION_NOANSWER) + { + sprintf ((*je)->textinfo, "No answer for this SUBSCRIBE!"); + } else if (type == EXOSIP_SUBSCRIPTION_PROCEEDING) + { + sprintf ((*je)->textinfo, "SUBSCRIBE is being processed!"); + } else if (type == EXOSIP_SUBSCRIPTION_ANSWERED) + { + sprintf ((*je)->textinfo, "2xx received for SUBSCRIBE!"); + } else if (type == EXOSIP_SUBSCRIPTION_REDIRECTED) + { + sprintf ((*je)->textinfo, "3xx received for SUBSCRIBE!"); + } else if (type == EXOSIP_SUBSCRIPTION_REQUESTFAILURE) + { + sprintf ((*je)->textinfo, "4xx received for SUBSCRIBE!"); + } else if (type == EXOSIP_SUBSCRIPTION_SERVERFAILURE) + { + sprintf ((*je)->textinfo, "5xx received for SUBSCRIBE!"); + } else if (type == EXOSIP_SUBSCRIPTION_GLOBALFAILURE) + { + sprintf ((*je)->textinfo, "5xx received for SUBSCRIBE!"); + } else if (type == EXOSIP_SUBSCRIPTION_NOTIFY) + { + sprintf ((*je)->textinfo, "NOTIFY request for subscription!"); + } else if (type == EXOSIP_SUBSCRIPTION_RELEASED) + { + sprintf ((*je)->textinfo, "Subscription has terminate!"); + } else if (type == EXOSIP_IN_SUBSCRIPTION_NEW) + { + sprintf ((*je)->textinfo, "New incoming SUBSCRIBE!"); + } else if (type == EXOSIP_IN_SUBSCRIPTION_RELEASED) + { + sprintf ((*je)->textinfo, "Incoming Subscription has terminate!"); + } else + { + (*je)->textinfo[0] = '\0'; + } + return 0; +} + +void +eXosip_event_free (eXosip_event_t * je) +{ + if (je == NULL) + return; + if (je->request != NULL) + osip_message_free (je->request); + if (je->response != NULL) + osip_message_free (je->response); + if (je->ack != NULL) + osip_message_free (je->ack); + osip_free (je); +} + +void +report_event (eXosip_event_t * je, osip_message_t * sip) +{ + if (je != NULL) + { + eXosip_event_add (je); + } +} + +void +report_call_event (int evt, eXosip_call_t * jc, + eXosip_dialog_t * jd, osip_transaction_t * tr) +{ + eXosip_event_t *je; + + je = eXosip_event_init_for_call (evt, jc, jd, tr); + report_event (je, NULL); +} + +void +report_options_event (int evt, osip_transaction_t * tr) +{ + eXosip_event_t *je; + + eXosip_event_init (&je, evt); + if (je == NULL) + return; + + if (tr != NULL) + je->tid = tr->transactionid; + + _eXosip_event_fill_messages (je, tr); + report_event (je, NULL); +} + +int +eXosip_event_add (eXosip_event_t * je) +{ + int i = osip_fifo_add (eXosip.j_events, (void *) je); + + osip_cond_signal ((struct osip_cond *) eXosip.j_cond); + __eXosip_wakeup_event (); + return i; +} + +#if 0 +#ifdef CLOCK_REALTIME +/* if CLOCK_REALTIME exist, then clock_gettime should be defined */ + +#define OSIP_CLOCK_REALTIME CLOCK_REALTIME + +void +__eXosip_clock_gettime (clockid_t cid, struct timespec *time) +{ + clock_gettime (cid, time); +} + +#elif defined (WIN32) || defined (_WIN32_WCE) + +#include <sys/types.h> +#include <sys/timeb.h> + +#define OSIP_CLOCK_REALTIME 4002 + +void +__eXosip_clock_gettime (unsigned int clock_id, struct timespec *time) +{ + struct _timeb time_val; + + if (clock_id != OSIP_CLOCK_REALTIME) + return; + + _ftime (&time_val); + time->tv_sec = time_val.time; + time->tv_nsec = time_val.millitm * 1000000; + return; +} +#endif +#endif + +eXosip_event_t * +eXosip_event_wait (int tv_s, int tv_ms) +{ + eXosip_event_t *je = NULL; + +#if 0 /* this does not seems to work. by now */ +#if defined (CLOCK_REALTIME) || defined (WIN32) || defined (_WIN32_WCE) + int i; + + struct timespec deadline; + struct timespec interval; + long tot_ms = (tv_s * 1000) + tv_ms; + + static struct osip_mutex *mlock = NULL; + + if (mlock == NULL) + mlock = osip_mutex_init (); + + je = (eXosip_event_t *) osip_fifo_tryget (eXosip.j_events); + if (je) + return je; + + interval.tv_sec = tot_ms / 1000; + interval.tv_nsec = (tot_ms % 1000) * 1000000L; + + __eXosip_clock_gettime (OSIP_CLOCK_REALTIME, &deadline); + + if ((deadline.tv_nsec += interval.tv_nsec) >= 1000000000L) + { + deadline.tv_nsec -= 1000000000L; + deadline.tv_sec += 1; + } else + deadline.tv_nsec += interval.tv_nsec; + + deadline.tv_sec += interval.tv_sec; + + i = osip_cond_timedwait ((struct osip_cond *) eXosip.j_cond, + (struct osip_mutex *) mlock, &deadline); + +#endif +#else + /* basic replacement */ + { + fd_set fdset; + struct timeval tv; + int max, i; + + FD_ZERO (&fdset); +#if defined (WIN32) || defined (_WIN32_WCE) + FD_SET ((unsigned int) jpipe_get_read_descr (eXosip.j_socketctl_event), + &fdset); +#else + FD_SET (jpipe_get_read_descr (eXosip.j_socketctl_event), &fdset); +#endif + max = jpipe_get_read_descr (eXosip.j_socketctl_event); + tv.tv_sec = tv_s; + tv.tv_usec = tv_ms * 1000; + + je = (eXosip_event_t *) osip_fifo_tryget (eXosip.j_events); + if (je != NULL) + return je; + + if (tv_s == 0 && tv_ms == 0) + return NULL; + + i = select (max + 1, &fdset, NULL, NULL, &tv); + if (i <= 0) + return 0; + + if (FD_ISSET (jpipe_get_read_descr (eXosip.j_socketctl_event), &fdset)) + { + char buf[500]; + + jpipe_read (eXosip.j_socketctl_event, buf, 499); + } + + je = (eXosip_event_t *) osip_fifo_tryget (eXosip.j_events); + if (je != NULL) + return je; + } +#endif + + return je; +} + +eXosip_event_t * +eXosip_event_get () +{ + eXosip_event_t *je; + + je = (eXosip_event_t *) osip_fifo_get (eXosip.j_events); + return je; +} diff --git a/exosip2/jnotify.c b/exosip2/jnotify.c new file mode 100644 index 0000000000000000000000000000000000000000..ab9049a173bdbbff8e0041d7e30308caa8df8e5a --- /dev/null +++ b/exosip2/jnotify.c @@ -0,0 +1,202 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +osip_transaction_t * +eXosip_find_last_inc_subscribe (eXosip_notify_t * jn, eXosip_dialog_t * jd) +{ + osip_transaction_t *inc_tr; + int pos; + + inc_tr = NULL; + pos = 0; + if (jd != NULL) + { + while (!osip_list_eol (jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get (jd->d_inc_trs, pos); + if (0 == strcmp (inc_tr->cseq->method, "SUBSCRIBE")) + break; + else + inc_tr = NULL; + pos++; + } + } else + inc_tr = NULL; + + if (inc_tr == NULL) + return jn->n_inc_tr; /* can be NULL */ + + return inc_tr; +} + + +osip_transaction_t * +eXosip_find_last_out_notify (eXosip_notify_t * jn, eXosip_dialog_t * jd) +{ + osip_transaction_t *out_tr; + int pos; + + out_tr = NULL; + pos = 0; + if (jd != NULL) + { + while (!osip_list_eol (jd->d_out_trs, pos)) + { + out_tr = osip_list_get (jd->d_out_trs, pos); + if (0 == strcmp (out_tr->cseq->method, "NOTIFY")) + return out_tr; + pos++; + } + } + + return NULL; +} + +int +eXosip_notify_init (eXosip_notify_t ** jn, osip_message_t * inc_subscribe) +{ + osip_contact_t *co; + char *uri; + int i; + char locip[50]; + +#ifdef SM + eXosip_get_localip_from_via (inc_subscribe, locip, 49); +#else + i = _eXosip_find_protocol(inc_subscribe); + if (i==IPPROTO_UDP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, 49); + } + else if (i==IPPROTO_TCP) + { + eXosip_guess_ip_for_via (eXosip.net_interfaces[1].net_ip_family, locip, 49); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol (default to UDP)\n")); + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, 49); + return -1; + } + +#endif + if (inc_subscribe == NULL + || inc_subscribe->to == NULL || inc_subscribe->to->url == NULL) + return -1; + co = (osip_contact_t *) osip_list_get (inc_subscribe->contacts, 0); + if (co == NULL || co->url == NULL) + return -1; + + *jn = (eXosip_notify_t *) osip_malloc (sizeof (eXosip_notify_t)); + if (*jn == NULL) + return -1; + memset (*jn, 0, sizeof (eXosip_notify_t)); + + i = osip_uri_to_str (co->url, &uri); + if (i != 0) + { + osip_free (*jn); + *jn = NULL; + return -1; + } + osip_strncpy ((*jn)->n_uri, uri, 254); + osip_free (uri); + + return 0; +} + +void +eXosip_notify_free (eXosip_notify_t * jn) +{ + /* ... */ + + eXosip_dialog_t *jd; + + for (jd = jn->n_dialogs; jd != NULL; jd = jn->n_dialogs) + { + REMOVE_ELEMENT (jn->n_dialogs, jd); + eXosip_dialog_free (jd); + } + + __eXosip_delete_jinfo (jn->n_inc_tr); + __eXosip_delete_jinfo (jn->n_out_tr); + if (jn->n_inc_tr != NULL) + osip_list_add (eXosip.j_transactions, jn->n_inc_tr, 0); + if (jn->n_out_tr != NULL) + osip_list_add (eXosip.j_transactions, jn->n_out_tr, 0); + osip_free (jn); +} + +int +_eXosip_notify_set_refresh_interval (eXosip_notify_t * jn, + osip_message_t * inc_subscribe) +{ + osip_header_t *exp; + int now; + + now = time (NULL); + if (jn == NULL || inc_subscribe == NULL) + return -1; + + osip_message_get_expires (inc_subscribe, 0, &exp); + if (exp == NULL || exp->hvalue == NULL) + jn->n_ss_expires = now + 600; + else + { + jn->n_ss_expires = osip_atoi (exp->hvalue); + if (jn->n_ss_expires != -1) + jn->n_ss_expires = now + jn->n_ss_expires; + else /* on error, set it to default */ + jn->n_ss_expires = now + 600; + } + + return 0; +} + +void +_eXosip_notify_add_expires_in_2XX_for_subscribe (eXosip_notify_t * jn, + osip_message_t * answer) +{ + char tmp[20]; + int now; + + now = time (NULL); + + if (jn->n_ss_expires - now < 0) + { + tmp[0] = '0'; + tmp[1] = '\0'; + } else + { + sprintf (tmp, "%i", jn->n_ss_expires - now); + } + osip_message_set_expires (answer, tmp); +} diff --git a/exosip2/jpipe.c b/exosip2/jpipe.c new file mode 100644 index 0000000000000000000000000000000000000000..004306aa77f49cd8f64f29218c4a98cc3d332e9b --- /dev/null +++ b/exosip2/jpipe.c @@ -0,0 +1,230 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "jpipe.h" + +#ifndef WIN32 + +jpipe_t * +jpipe () +{ + jpipe_t *my_pipe = (jpipe_t *) osip_malloc (sizeof (jpipe_t)); + + if (my_pipe == NULL) + return NULL; + + if (0 != pipe (my_pipe->pipes)) + { + osip_free (my_pipe); + return NULL; + } + return my_pipe; +} + +int +jpipe_close (jpipe_t * apipe) +{ + if (apipe == NULL) + return -1; + close (apipe->pipes[0]); + close (apipe->pipes[1]); + osip_free (apipe); + return 0; +} + + +/** + * Write in a pipe. + */ +int +jpipe_write (jpipe_t * apipe, const void *buf, int count) +{ + if (apipe == NULL) + return -1; + return write (apipe->pipes[1], buf, count); +} + +/** + * Read in a pipe. + */ +int +jpipe_read (jpipe_t * apipe, void *buf, int count) +{ + if (apipe == NULL) + return -1; + return read (apipe->pipes[0], buf, count); +} + +/** + * Get descriptor of reading pipe. + */ +int +jpipe_get_read_descr (jpipe_t * apipe) +{ + if (apipe == NULL) + return -1; + return apipe->pipes[0]; +} + +#else + +jpipe_t * +jpipe () +{ + int s = 0; + int timeout = 0; + static int aport = 10500; + struct sockaddr_in raddr; + int j; + + jpipe_t *my_pipe = (jpipe_t *) osip_malloc (sizeof (jpipe_t)); + + if (my_pipe == NULL) + return NULL; + + s = (int) socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (0 > s) + { + osip_free (my_pipe); + return NULL; + } + my_pipe->pipes[1] = (int) socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (0 > my_pipe->pipes[1]) + { + closesocket (s); + osip_free (my_pipe); + return NULL; + } + + raddr.sin_addr.s_addr = inet_addr ("127.0.0.1"); + raddr.sin_family = AF_INET; + + j = 50; + while (aport++ && j-- > 0) + { + raddr.sin_port = htons ((short) aport); + if (bind (s, (struct sockaddr *) &raddr, sizeof (raddr)) < 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_WARNING, NULL, + "Failed to bind one local socket %i!\n", aport)); + } else + break; + } + + if (j == 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Failed to bind a local socket, aborting!\n")); + closesocket (s); + closesocket (my_pipe->pipes[1]); + osip_free (my_pipe); + } + + j = listen (s, 1); + if (j != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Failed to listen on a local socket, aborting!\n")); + closesocket (s); + closesocket (my_pipe->pipes[1]); + osip_free (my_pipe); + } + + j = setsockopt (my_pipe->pipes[1], + SOL_SOCKET, + SO_RCVTIMEO, (const char *) &timeout, sizeof (timeout)); + if (j != NO_ERROR) + { + /* failed for some reason... */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "udp plugin; cannot set O_NONBLOCK to the file desciptor!\n")); + closesocket (s); + closesocket (my_pipe->pipes[1]); + osip_free (my_pipe); + } + + connect (my_pipe->pipes[1], (struct sockaddr *) &raddr, sizeof (raddr)); + + my_pipe->pipes[0] = accept (s, NULL, NULL); + + if (my_pipe->pipes[0] <= 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "udp plugin; Failed to call accept!\n")); + closesocket (s); + closesocket (my_pipe->pipes[1]); + osip_free (my_pipe); + } + + return my_pipe; +} + +int +jpipe_close (jpipe_t * apipe) +{ + if (apipe == NULL) + return -1; + closesocket (apipe->pipes[0]); + closesocket (apipe->pipes[1]); + osip_free (apipe); + return 0; +} + + +/** + * Write in a pipe. + */ +int +jpipe_write (jpipe_t * apipe, const void *buf, int count) +{ + if (apipe == NULL) + return -1; + return send (apipe->pipes[1], buf, count, 0); +} + +/** + * Read in a pipe. + */ +int +jpipe_read (jpipe_t * apipe, void *buf, int count) +{ + if (apipe == NULL) + return -1; + return recv (apipe->pipes[0], buf, count, 0 /* MSG_DONTWAIT */ ); /* BUG?? */ +} + +/** + * Get descriptor of reading pipe. + */ +int +jpipe_get_read_descr (jpipe_t * apipe) +{ + if (apipe == NULL) + return -1; + return apipe->pipes[0]; +} + +#endif diff --git a/exosip2/jpipe.h b/exosip2/jpipe.h new file mode 100644 index 0000000000000000000000000000000000000000..1a8862c4f6d70efe7117c64a670a0be89e3f741b --- /dev/null +++ b/exosip2/jpipe.h @@ -0,0 +1,109 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef _JPIPE_H_ +#define _JPIPE_H_ + +#include <eXosip2/eXosip.h> + +#ifndef WIN32 +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#endif + +#ifdef WIN32 +#include <windows.h> +#endif + +/** + * @file jpipe.h + * @brief PPL Pipe Handling Routines + */ + +/** + * @defgroup JPIPE Pipe Handling + * @ingroup PPL + * @{ + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef WIN32 + +/** + * Structure for storing a pipe descriptor + * @defvar jpipe_t + */ + typedef struct jpipe_t jpipe_t; + + struct jpipe_t + { + int pipes[2]; + }; + +#else + +/** + * Structure for storing a pipe descriptor + * @defvar ppl_pipe_t + */ + typedef struct jpipe_t jpipe_t; + + struct jpipe_t + { + int pipes[2]; + }; + +#endif + +/** + * Get New pipe pair. + */ + jpipe_t *jpipe (void); + +/** + * Close pipe + */ + int jpipe_close (jpipe_t * apipe); + +/** + * Write in a pipe. + */ + int jpipe_write (jpipe_t * pipe, const void *buf, int count); + +/** + * Read in a pipe. + */ + int jpipe_read (jpipe_t * pipe, void *buf, int count); + +/** + * Get descriptor of reading pipe. + */ + int jpipe_get_read_descr (jpipe_t * pipe); + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif diff --git a/exosip2/jpublish.c b/exosip2/jpublish.c new file mode 100644 index 0000000000000000000000000000000000000000..ef75828af598e781a45691b3be78b257e084266b --- /dev/null +++ b/exosip2/jpublish.c @@ -0,0 +1,122 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +int +_eXosip_pub_update (eXosip_pub_t ** pub, osip_transaction_t * tr, + osip_message_t * answer) +{ + eXosip_pub_t *jpub; + + *pub = NULL; + + for (jpub = eXosip.j_pub; jpub != NULL; jpub = jpub->next) + { + if (jpub->p_last_tr == NULL) + { /*bug? */ + } else if (tr == jpub->p_last_tr) + { + /* update the sip_etag parameter */ + if (answer == NULL) + { /* bug? */ + } else if (MSG_IS_STATUS_2XX (answer)) + { + osip_header_t *sip_etag = NULL; + + osip_message_header_get_byname (answer, "SIP-ETag", 0, &sip_etag); + if (sip_etag != NULL && sip_etag->hvalue != NULL) + snprintf (jpub->p_sip_etag, 64, "%s", sip_etag->hvalue); + } + *pub = jpub; + return 0; + } + } + return -1; +} + +int +_eXosip_pub_find_by_aor (eXosip_pub_t ** pub, const char *aor) +{ + eXosip_pub_t *jpub; + eXosip_pub_t *ptr; + time_t now; + + *pub = NULL; + + /* delete expired publications */ + now = time (NULL); + ptr = eXosip.j_pub; + for (jpub = ptr; jpub != NULL; jpub = ptr) + { + ptr = jpub->next; + if (now - jpub->p_expires > 60) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_WARNING, NULL, + "eXosip: removing expired publication!")); + REMOVE_ELEMENT (eXosip.j_pub, jpub); + _eXosip_pub_free (jpub); + } + } + + for (jpub = eXosip.j_pub; jpub != NULL; jpub = jpub->next) + { + if (osip_strcasecmp (aor, jpub->p_aor) == 0) + { + *pub = jpub; + return 0; + } + } + return -1; +} + +int +_eXosip_pub_init (eXosip_pub_t ** pub, const char *aor, const char *exp) +{ + eXosip_pub_t *jpub; + + *pub = NULL; + + jpub = (eXosip_pub_t *) osip_malloc (sizeof (eXosip_pub_t)); + if (jpub == 0) + return -1; + memset (jpub, 0, sizeof (eXosip_pub_t)); + snprintf (jpub->p_aor, 256, "%s", aor); + + jpub->p_expires = atoi (exp) + time (NULL); + jpub->p_period = atoi (exp); + + *pub = jpub; + return 0; +} + +void +_eXosip_pub_free (eXosip_pub_t * pub) +{ + if (pub->p_last_tr != NULL) + osip_list_add (eXosip.j_transactions, pub->p_last_tr, 0); + osip_free (pub); +} diff --git a/exosip2/jreg.c b/exosip2/jreg.c new file mode 100644 index 0000000000000000000000000000000000000000..ecd32872b1ef47e44c3cb12ba779d0a5e06b1cd3 --- /dev/null +++ b/exosip2/jreg.c @@ -0,0 +1,104 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +int +eXosip_reg_init (eXosip_reg_t ** jr, const char *from, const char *proxy, + const char *contact) +{ + static int r_id; + + *jr = (eXosip_reg_t *) osip_malloc (sizeof (eXosip_reg_t)); + if (*jr == NULL) + return -1; + + if (r_id > 1000000) /* keep it non-negative */ + r_id = 0; + + memset (*jr, '\0', sizeof (eXosip_reg_t)); + + (*jr)->r_id = ++r_id; + (*jr)->r_reg_period = 3600; /* delay between registration */ + (*jr)->r_aor = osip_strdup (from); /* sip identity */ + (*jr)->r_contact = osip_strdup (contact); /* sip identity */ + (*jr)->r_registrar = osip_strdup (proxy); /* registrar */ + + return 0; +} + +void +eXosip_reg_free (eXosip_reg_t * jreg) +{ + + osip_free (jreg->r_aor); + osip_free (jreg->r_contact); + osip_free (jreg->r_registrar); + + if (jreg->r_last_tr != NULL) + { + if (jreg->r_last_tr->state == IST_TERMINATED || + jreg->r_last_tr->state == ICT_TERMINATED || + jreg->r_last_tr->state == NICT_TERMINATED || + jreg->r_last_tr->state == NIST_TERMINATED) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Release a terminated transaction\n")); + __eXosip_delete_jinfo (jreg->r_last_tr); + if (jreg->r_last_tr != NULL) + osip_list_add (eXosip.j_transactions, jreg->r_last_tr, 0); + } else + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Release a non-terminated transaction\n")); + __eXosip_delete_jinfo (jreg->r_last_tr); + if (jreg->r_last_tr != NULL) + osip_list_add (eXosip.j_transactions, jreg->r_last_tr, 0); + } + } + + osip_free (jreg); +} + +int +_eXosip_reg_find (eXosip_reg_t ** reg, osip_transaction_t * tr) +{ + eXosip_reg_t *jreg; + + *reg = NULL; + if (tr == NULL) + return -1; + + for (jreg = eXosip.j_reg; jreg != NULL; jreg = jreg->next) + { + if (jreg->r_last_tr == tr) + { + *reg = jreg; + return 0; + } + } + return -1; +} diff --git a/exosip2/jrequest.c b/exosip2/jrequest.c new file mode 100644 index 0000000000000000000000000000000000000000..ae24979e2f11046876f104ad26fa793512c6a32e --- /dev/null +++ b/exosip2/jrequest.c @@ -0,0 +1,999 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" + +#ifndef WIN32 +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#ifdef __APPLE_CC__ +#include <unistd.h> +#endif +#else +#include <windows.h> +#include <Iphlpapi.h> +#endif + +extern eXosip_t eXosip; + +/* Private functions */ +static int dialog_fill_route_set (osip_dialog_t * dialog, + osip_message_t * request); + +/* should use cryptographically random identifier is RECOMMENDED.... */ +/* by now this should lead to identical call-id when application are + started at the same time... */ +char * +osip_call_id_new_random () +{ + char *tmp = (char *) osip_malloc (33); + unsigned int number = osip_build_random_number (); + + sprintf (tmp, "%u", number); + return tmp; +} + +char * +osip_from_tag_new_random (void) +{ + return osip_call_id_new_random (); +} + +char * +osip_to_tag_new_random (void) +{ + return osip_call_id_new_random (); +} + +unsigned int +via_branch_new_random (void) +{ + return osip_build_random_number (); +} + +/* prepare a minimal request (outside of a dialog) with required headers */ +/* + method is the type of request. ("INVITE", "REGISTER"...) + to is the remote target URI + transport is either "TCP" or "UDP" (by now, only UDP is implemented!) +*/ +int +generating_request_out_of_dialog (osip_message_t ** dest, const char *method, + const char *to, const char *transport, + const char *from, const char *proxy) +{ + /* Section 8.1: + A valid request contains at a minimum "To, From, Call-iD, Cseq, + Max-Forwards and Via + */ + int i; + osip_message_t *request; + char locip[50]; + int doing_register; + char *register_callid_number = NULL; + struct eXosip_net *net; + + if (0==osip_strcasecmp(transport, "udp")) + net = &eXosip.net_interfaces[0]; + else if (0==osip_strcasecmp(transport, "tcp")) + net = &eXosip.net_interfaces[1]; + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol (default to UDP)\n")); + net = &eXosip.net_interfaces[0]; + } + + *dest = NULL; + + i = osip_message_init (&request); + if (i != 0) + return -1; + + /* prepare the request-line */ + osip_message_set_method (request, osip_strdup (method)); + osip_message_set_version (request, osip_strdup ("SIP/2.0")); + osip_message_set_status_code (request, 0); + osip_message_set_reason_phrase (request, NULL); + + doing_register = 0 == strcmp ("REGISTER", method); + + if (doing_register) + { + osip_uri_init (&(request->req_uri)); + i = osip_uri_parse (request->req_uri, proxy); + if (i != 0) + { + goto brood_error_1; + } + osip_message_set_to (request, from); + } else + { + /* in any cases except REGISTER: */ + i = osip_message_set_to (request, to); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: callee address does not seems to be a sipurl: %s\n", + to)); + goto brood_error_1; + } + if (proxy != NULL && proxy[0] != 0) + { /* equal to a pre-existing route set */ + /* if the pre-existing route set contains a "lr" (compliance + with bis-08) then the req_uri should contains the remote target + URI */ + osip_uri_param_t *lr_param; + osip_route_t *o_proxy; + +#ifndef __VXWORKS_OS__ + osip_route_init (&o_proxy); +#else + osip_route_init2 (&o_proxy); +#endif + i = osip_route_parse (o_proxy, proxy); + if (i != 0) + { + osip_route_free (o_proxy); + goto brood_error_1; + } + + osip_uri_uparam_get_byname (o_proxy->url, "lr", &lr_param); + if (lr_param != NULL) /* to is the remote target URI in this case! */ + { + osip_uri_clone (request->to->url, &(request->req_uri)); + /* "[request] MUST includes a Route header field containing + the route set values in order." */ + osip_list_add (request->routes, o_proxy, 0); + } else + /* if the first URI of route set does not contain "lr", the req_uri + is set to the first uri of route set */ + { + request->req_uri = o_proxy->url; + o_proxy->url = NULL; + osip_route_free (o_proxy); + /* add the route set */ + /* "The UAC MUST add a route header field containing + the remainder of the route set values in order. + The UAC MUST then place the remote target URI into + the route header field as the last value + */ + osip_message_set_route (request, to); + } + } else /* No route set (outbound proxy) is used */ + { + /* The UAC must put the remote target URI (to field) in the req_uri */ + i = osip_uri_clone (request->to->url, &(request->req_uri)); + if (i != 0) + goto brood_error_1; + } + } + /*guess the local ip since req uri is known */ +#ifdef SM + eXosip_get_localip_for (request->req_uri->host, locip, 49); +#else + if (0==osip_strcasecmp(transport, "udp")) + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, 49); + else if (0==osip_strcasecmp(transport, "tcp")) + eXosip_guess_ip_for_via (eXosip.net_interfaces[1].net_ip_family, locip, 49); + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol (default to UDP)\n")); + eXosip_guess_ip_for_via (eXosip.net_interfaces[0].net_ip_family, locip, 49); + } +#endif + /* set To and From */ + osip_message_set_from (request, from); + /* add a tag */ + osip_from_set_tag (request->from, osip_from_tag_new_random ()); + + /* set the cseq and call_id header */ + { + osip_call_id_t *callid; + osip_cseq_t *cseq; + char *num; + char *cidrand; + + /* call-id is always the same for REGISTRATIONS */ + i = osip_call_id_init (&callid); + if (i != 0) + goto brood_error_1; + cidrand = osip_call_id_new_random (); + osip_call_id_set_number (callid, cidrand); + if (doing_register) + register_callid_number = cidrand; + + osip_call_id_set_host (callid, osip_strdup (locip)); + request->call_id = callid; + + i = osip_cseq_init (&cseq); + if (i != 0) + goto brood_error_1; + num = osip_strdup (doing_register ? "1" : "20"); + osip_cseq_set_number (cseq, num); + osip_cseq_set_method (cseq, osip_strdup (method)); + request->cseq = cseq; + } + + /* always add the Max-Forward header */ + osip_message_set_max_forwards (request, "5"); /* a UA should start a request with 70 */ + +#define MASQUERADE_VIA +#ifdef MASQUERADE_VIA + /* should be useless with compliant UA */ + if (eXosip.net_interfaces[0].net_firewall_ip[0] != '\0') + { + char *c_address = request->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + + i = eXosip_get_addrinfo (&addrinfo, request->req_uri->host, 5060, IPPROTO_UDP); + if (i == 0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", + c_address)); + } + + if (eXosip_is_public_address (c_address)) + { + char tmp[200]; + + snprintf (tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", + transport, eXosip.net_interfaces[0].net_firewall_ip, + net->net_port, + via_branch_new_random ()); + osip_message_set_via (request, tmp); + } else + { + char tmp[200]; + + if (net->net_ip_family == AF_INET6) + snprintf (tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", + transport, locip, net->net_port, + via_branch_new_random ()); + else + snprintf (tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", + transport, locip, net->net_port, + via_branch_new_random ()); + osip_message_set_via (request, tmp); + } + } else + { + char tmp[200]; + + if (net->net_ip_family == AF_INET6) + snprintf (tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, net->net_port, + via_branch_new_random ()); + else + snprintf (tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", + transport, locip, net->net_port, + via_branch_new_random ()); + osip_message_set_via (request, tmp); + } + +#else + { + char tmp[200]; + + if (net->net_ip_family == AF_INET6) + spnrintf (tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, net->net_port, + via_branch_new_random ()); + else + spnrintf (tmp, 200, "SIP/2.0/%s %s:%s;branch=z9hG4bK%u", transport, + locip, net->net_port, + via_branch_new_random ()); + + osip_message_set_via (request, tmp); + } +#endif + + /* add specific headers for each kind of request... */ + + if (0 == strcmp ("INVITE", method) || 0 == strcmp ("SUBSCRIBE", method)) + { + char *contact; + osip_from_t *a_from; + int i; + + i = osip_from_init (&a_from); + if (i == 0) + i = osip_from_parse (a_from, from); + + if (i == 0 && a_from != NULL + && a_from->url != NULL && a_from->url->username != NULL) + { + contact = (char *) osip_malloc (50 + strlen (a_from->url->username)); + + if (eXosip.net_interfaces[0].net_firewall_ip[0] != '\0') + { + char *c_address = request->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + + i = eXosip_get_addrinfo (&addrinfo, request->req_uri->host, 5060, IPPROTO_TCP); + if (i == 0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", + c_address)); + } + + if (eXosip_is_public_address (c_address)) + { + sprintf (contact, "<sip:%s@%s:%s>", a_from->url->username, + eXosip.net_interfaces[0].net_firewall_ip, + net->net_port); + } else + { + sprintf (contact, "<sip:%s@%s:%s>", a_from->url->username, + locip, net->net_port); + } + } else + { + sprintf (contact, "<sip:%s@%s:%s>", a_from->url->username, + locip, net->net_port); + } + osip_message_set_contact (request, contact); + osip_free (contact); + } + osip_from_free (a_from); + + /* This is probably useless for other messages */ + osip_message_set_allow (request, "INVITE"); + osip_message_set_allow (request, "ACK"); + osip_message_set_allow (request, "UPDATE"); + osip_message_set_allow (request, "INFO"); + osip_message_set_allow (request, "CANCEL"); + osip_message_set_allow (request, "BYE"); + osip_message_set_allow (request, "OPTIONS"); + osip_message_set_allow (request, "REFER"); + osip_message_set_allow (request, "SUBSCRIBE"); + osip_message_set_allow (request, "NOTIFY"); + osip_message_set_allow (request, "MESSAGE"); + } + + if (0 == strcmp ("REGISTER", method)) + { + } else if (0 == strcmp ("INFO", method)) + { + } else if (0 == strcmp ("OPTIONS", method)) + { + osip_message_set_accept (request, "application/sdp"); + } + + osip_message_set_user_agent (request, eXosip.user_agent); + /* else if ... */ + *dest = request; + return 0; + +brood_error_1: + osip_message_free (request); + *dest = NULL; + return -1; +} + +int +generating_register (osip_message_t ** reg, char *transport, char *from, + char *proxy, char *contact, int expires) +{ + osip_from_t *a_from; + int i; + char locip[50]; + struct eXosip_net *net; + + i = generating_request_out_of_dialog (reg, "REGISTER", NULL, transport, from, proxy); + if (i != 0) + return -1; + + i = _eXosip_find_protocol(*reg); + if (i==IPPROTO_UDP) + net = &eXosip.net_interfaces[0]; + else if (i==IPPROTO_TCP) + net = &eXosip.net_interfaces[1]; + else + { + net = &eXosip.net_interfaces[0]; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol\n")); + return -1; + } + +#ifdef SM + eXosip_get_localip_for ((*reg)->req_uri->host, locip, 49); +#else + eXosip_guess_ip_for_via (net->net_ip_family, locip, 49); +#endif + + if (contact == NULL) + { + i = osip_from_init (&a_from); + if (i == 0) + i = osip_from_parse (a_from, from); + + if (i == 0 && a_from != NULL + && a_from->url != NULL && a_from->url->username != NULL) + { + contact = (char *) osip_malloc (50 + strlen (a_from->url->username)); + if (eXosip.net_interfaces[0].net_firewall_ip[0] != '\0') + { + char *c_address = (*reg)->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + + i = eXosip_get_addrinfo (&addrinfo, (*reg)->req_uri->host, 5060, IPPROTO_UDP); + if (i == 0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", + c_address)); + } + + if (eXosip_is_public_address (c_address)) + { + sprintf (contact, "<sip:%s@%s:%s>", a_from->url->username, + eXosip.net_interfaces[0].net_firewall_ip, + net->net_port); + } else + { + sprintf (contact, "<sip:%s@%s:%s>", a_from->url->username, + locip, net->net_port); + } + } else + { + sprintf (contact, "<sip:%s@%s:%s>", a_from->url->username, + locip, net->net_port); + } + + osip_message_set_contact (*reg, contact); + osip_free (contact); + } + osip_from_free (a_from); + } else + { + osip_message_set_contact (*reg, contact); + } + + { + char exp[10]; /* MUST never be ouside 1 and 3600 */ + + snprintf (exp, 9, "%i", expires); + osip_message_set_expires (*reg, exp); + } + + osip_message_set_content_length (*reg, "0"); + + return 0; +} + +int +generating_publish (osip_message_t ** message, const char *to, + const char *from, const char *route) +{ + int i; + + if (to != NULL && *to == '\0') + return -1; + + if (route != NULL && *route == '\0') + route = NULL; + + i = generating_request_out_of_dialog (message, "PUBLISH", to, "UDP", from, + route); + if (i != 0) + return -1; + + /* osip_message_set_organization(*message, "Jack's Org"); */ + + return 0; +} + +static int +dialog_fill_route_set (osip_dialog_t * dialog, osip_message_t * request) +{ + /* if the pre-existing route set contains a "lr" (compliance + with bis-08) then the req_uri should contains the remote target + URI */ + int i; + int pos = 0; + osip_uri_param_t *lr_param; + osip_route_t *route; + char *last_route; + + /* AMD bug: fixed 17/06/2002 */ + +#ifdef OSIP_FUTURE_FIX_2_3 + route = (osip_route_t *) osip_list_get (dialog->route_set, 0); +#else + if (dialog->type == CALLER) + { + pos = osip_list_size (dialog->route_set) - 1; + route = (osip_route_t *) osip_list_get (dialog->route_set, pos); + } else + route = (osip_route_t *) osip_list_get (dialog->route_set, 0); +#endif + + osip_uri_uparam_get_byname (route->url, "lr", &lr_param); + if (lr_param != NULL) /* the remote target URI is the req_uri! */ + { + i = osip_uri_clone (dialog->remote_contact_uri->url, &(request->req_uri)); + if (i != 0) + return -1; + /* "[request] MUST includes a Route header field containing + the route set values in order." */ + /* AMD bug: fixed 17/06/2002 */ + pos = 0; /* first element is at index 0 */ + while (!osip_list_eol (dialog->route_set, pos)) + { + osip_route_t *route2; + + route = osip_list_get (dialog->route_set, pos); + i = osip_route_clone (route, &route2); + if (i != 0) + return -1; +#ifdef OSIP_FUTURE_FIX_2_3 + osip_list_add (request->routes, route2, -1); +#else + if (dialog->type == CALLER) + osip_list_add (request->routes, route2, 0); + else + osip_list_add (request->routes, route2, -1); + pos++; +#endif + } + return 0; + } + + /* if the first URI of route set does not contain "lr", the req_uri + is set to the first uri of route set */ + + + i = osip_uri_clone (route->url, &(request->req_uri)); + if (i != 0) + return -1; + /* add the route set */ + /* "The UAC MUST add a route header field containing + the remainder of the route set values in order. */ + pos = 0; /* yes it is */ + + while (!osip_list_eol (dialog->route_set, pos)) /* not the first one in the list */ + { + osip_route_t *route2; + + route = osip_list_get (dialog->route_set, pos); + i = osip_route_clone (route, &route2); + if (i != 0) + return -1; +#ifdef OSIP_FUTURE_FIX_2_3 + if (!osip_list_eol (dialog->route_set, pos + 1)) + osip_list_add (request->routes, route2, -1); + else + osip_route_free (route2); +#else + if (dialog->type == CALLER) + { + if (pos != osip_list_size (dialog->route_set) - 1) + osip_list_add (request->routes, route2, 0); + else + osip_route_free (route2); + } else + { + if (!osip_list_eol (dialog->route_set, pos + 1)) + osip_list_add (request->routes, route2, -1); + else + osip_route_free (route2); + } +#endif + pos++; + } + + /* The UAC MUST then place the remote target URI into + the route header field as the last value */ + i = osip_uri_to_str (dialog->remote_contact_uri->url, &last_route); + if (i != 0) + return -1; + i = osip_message_set_route (request, last_route); + osip_free (last_route); + if (i != 0) + { + return -1; + } + + /* route header and req_uri set */ + return 0; +} + +int +_eXosip_build_request_within_dialog (osip_message_t ** dest, + const char *method, + osip_dialog_t * dialog, const char *transport) +{ + int i; + osip_message_t *request; + char locip[50]; + struct eXosip_net *net; + + i = osip_message_init (&request); + if (i != 0) + return -1; + + if (dialog->remote_contact_uri == NULL) + { + /* this dialog is probably not established! or the remote UA + is not compliant with the latest RFC + */ + osip_message_free (request); + return -1; + } + + if (0==osip_strcasecmp(transport, "udp")) + net = &eXosip.net_interfaces[0]; + else if (0==osip_strcasecmp(transport, "tcp")) + net = &eXosip.net_interfaces[1]; + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol -%s- (default to UDP)\n")); + net = &eXosip.net_interfaces[0]; + } + +#ifdef SM + eXosip_get_localip_for (dialog->remote_contact_uri->url->host, locip, 49); +#else + eXosip_guess_ip_for_via (net->net_ip_family, locip, 49); +#endif + /* prepare the request-line */ + request->sip_method = osip_strdup (method); + request->sip_version = osip_strdup ("SIP/2.0"); + request->status_code = 0; + request->reason_phrase = NULL; + + /* and the request uri???? */ + if (osip_list_eol (dialog->route_set, 0)) + { + /* The UAC must put the remote target URI (to field) in the req_uri */ + i = osip_uri_clone (dialog->remote_contact_uri->url, &(request->req_uri)); + if (i != 0) + goto grwd_error_1; + } else + { + /* fill the request-uri, and the route headers. */ + dialog_fill_route_set (dialog, request); + } + + /* To and From already contains the proper tag! */ + i = osip_to_clone (dialog->remote_uri, &(request->to)); + if (i != 0) + goto grwd_error_1; + i = osip_from_clone (dialog->local_uri, &(request->from)); + if (i != 0) + goto grwd_error_1; + + /* set the cseq and call_id header */ + osip_message_set_call_id (request, dialog->call_id); + + if (0 == strcmp ("ACK", method)) + { + osip_cseq_t *cseq; + char *tmp; + + i = osip_cseq_init (&cseq); + if (i != 0) + goto grwd_error_1; + tmp = osip_malloc (20); + sprintf (tmp, "%i", dialog->local_cseq); + osip_cseq_set_number (cseq, tmp); + osip_cseq_set_method (cseq, osip_strdup (method)); + request->cseq = cseq; + } else + { + osip_cseq_t *cseq; + char *tmp; + + i = osip_cseq_init (&cseq); + if (i != 0) + goto grwd_error_1; + dialog->local_cseq++; /* we should we do that?? */ + tmp = osip_malloc (20); + sprintf (tmp, "%i", dialog->local_cseq); + osip_cseq_set_number (cseq, tmp); + osip_cseq_set_method (cseq, osip_strdup (method)); + request->cseq = cseq; + } + + /* always add the Max-Forward header */ + osip_message_set_max_forwards (request, "5"); /* a UA should start a request with 70 */ + + + /* even for ACK for 2xx (ACK within a dialog), the branch ID MUST + be a new ONE! */ +#ifdef MASQUERADE_VIA + /* should be useless with compliant UA */ + if (eXosip.net_interfaces[0].net_firewall_ip[0] != '\0') + { + char *c_address = request->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + + i = eXosip_get_addrinfo (&addrinfo, request->req_uri->host, 5060, IPPROTO_UDP); + if (i == 0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", + c_address)); + } + + if (eXosip_is_public_address (c_address)) + { + char tmp[200]; + + sprintf (tmp, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", transport, + eXosip.net_interfaces[0].net_firewall_ip, + net->net_port, + via_branch_new_random ()); + osip_message_set_via (request, tmp); + } else + { + char tmp[200]; + + if (eXosip.net_interfaces[0].net_ip_family == AF_INET6) + snprintf (tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", + transport, locip, net->net_port, + via_branch_new_random ()); + else + snprintf (tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", + transport, locip, net->net_port, + via_branch_new_random ()); + + osip_message_set_via (request, tmp); + } + } else + { + char tmp[200]; + + if (net->net_ip_family == AF_INET6) + snprintf (tmp, 200, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, net->net_port, + via_branch_new_random ()); + else + snprintf (tmp, 200, "SIP/2.0/%s %s:%s;rport;branch=z9hG4bK%u", + transport, locip, net->net_port, + via_branch_new_random ()); + + osip_message_set_via (request, tmp); + } + +#else + { + char tmp[200]; + + if (net->net_ip_family == AF_INET6) + sprintf (tmp, "SIP/2.0/%s [%s]:%s;branch=z9hG4bK%u", transport, + locip, net->net_port, + via_branch_new_random ()); + else + sprintf (tmp, "SIP/2.0/%s %s:%s;branch=z9hG4bK%u", transport, + locip, net->net_port, + via_branch_new_random ()); + + osip_message_set_via (request, tmp); + } +#endif + + /* add specific headers for each kind of request... */ + + { + char contact[200]; + + if (net->net_firewall_ip[0] != '\0') + { + char *c_address = request->req_uri->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + + i = eXosip_get_addrinfo (&addrinfo, request->req_uri->host, 5060, IPPROTO_UDP); + if (i == 0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", + c_address)); + } + + if (eXosip_is_public_address (c_address)) + { + sprintf (contact, "<sip:%s@%s:%s>", + dialog->local_uri->url->username, + eXosip.net_interfaces[0].net_firewall_ip, + net->net_port); + } else + { + sprintf (contact, "<sip:%s@%s:%s>", + dialog->local_uri->url->username, locip, + net->net_port); + } + } else + { + sprintf (contact, "<sip:%s@%s:%s>", dialog->local_uri->url->username, + locip, net->net_port); + } + osip_message_set_contact (request, contact); + /* Here we'll add the supported header if it's needed! */ + /* the require header must be added by the upper layer if needed */ + } + + if (0 == strcmp ("NOTIFY", method)) + { + } else if (0 == strcmp ("INFO", method)) + { + + } else if (0 == strcmp ("OPTIONS", method)) + { + osip_message_set_accept (request, "application/sdp"); + } else if (0 == strcmp ("ACK", method)) + { + /* The ACK MUST contains the same credential than the INVITE!! */ + /* TODO... */ + } + + osip_message_set_user_agent (request, eXosip.user_agent); + /* else if ... */ + *dest = request; + return 0; + + /* grwd_error_2: */ + dialog->local_cseq--; +grwd_error_1: + osip_message_free (request); + *dest = NULL; + return -1; +} + +/* this request is only build within a dialog!! */ +int +generating_bye (osip_message_t ** bye, osip_dialog_t * dialog, char *transport) +{ + int i; + + i = _eXosip_build_request_within_dialog (bye, "BYE", dialog, transport); + if (i != 0) + return -1; + + return 0; +} + +/* It is RECOMMENDED to only cancel INVITE request */ +int +generating_cancel (osip_message_t ** dest, osip_message_t * request_cancelled) +{ + int i; + osip_message_t *request; + + i = osip_message_init (&request); + if (i != 0) + return -1; + + /* prepare the request-line */ + osip_message_set_method (request, osip_strdup ("CANCEL")); + osip_message_set_version (request, osip_strdup ("SIP/2.0")); + osip_message_set_status_code (request, 0); + osip_message_set_reason_phrase (request, NULL); + + i = osip_uri_clone (request_cancelled->req_uri, &(request->req_uri)); + if (i != 0) + goto gc_error_1; + + i = osip_to_clone (request_cancelled->to, &(request->to)); + if (i != 0) + goto gc_error_1; + i = osip_from_clone (request_cancelled->from, &(request->from)); + if (i != 0) + goto gc_error_1; + + /* set the cseq and call_id header */ + i = osip_call_id_clone (request_cancelled->call_id, &(request->call_id)); + if (i != 0) + goto gc_error_1; + i = osip_cseq_clone (request_cancelled->cseq, &(request->cseq)); + if (i != 0) + goto gc_error_1; + osip_free (request->cseq->method); + request->cseq->method = osip_strdup ("CANCEL"); + + /* copy ONLY the top most Via Field (this method is also used by proxy) */ + { + osip_via_t *via; + osip_via_t *via2; + + i = osip_message_get_via (request_cancelled, 0, &via); + if (i != 0) + goto gc_error_1; + i = osip_via_clone (via, &via2); + if (i != 0) + goto gc_error_1; + osip_list_add (request->vias, via2, -1); + } + + /* add the same route-set than in the previous request */ + { + int pos = 0; + osip_route_t *route; + osip_route_t *route2; + + while (!osip_list_eol (request_cancelled->routes, pos)) + { + route = (osip_route_t *) osip_list_get (request_cancelled->routes, pos); + i = osip_route_clone (route, &route2); + if (i != 0) + goto gc_error_1; + osip_list_add (request->routes, route2, -1); + pos++; + } + } + + osip_message_set_max_forwards (request, "70"); /* a UA should start a request with 70 */ + osip_message_set_user_agent (request, eXosip.user_agent); + + *dest = request; + return 0; + +gc_error_1: + osip_message_free (request); + *dest = NULL; + return -1; +} + diff --git a/exosip2/jresponse.c b/exosip2/jresponse.c new file mode 100644 index 0000000000000000000000000000000000000000..6135f56505c1594b2191af1bb6c242a3dc5b3ab9 --- /dev/null +++ b/exosip2/jresponse.c @@ -0,0 +1,736 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + + +int +_eXosip_build_response_default (osip_message_t ** dest, + osip_dialog_t * dialog, int status, + osip_message_t * request) +{ + osip_generic_param_t *tag; + osip_message_t *response; + int pos; + int i; + + *dest = NULL; + if (request == NULL) + return -1; + + i = osip_message_init (&response); + if (i != 0) + return -1; + /* initialise osip_message_t structure */ + /* yet done... */ + + response->sip_version = (char *) osip_malloc (8 * sizeof (char)); + sprintf (response->sip_version, "SIP/2.0"); + osip_message_set_status_code (response, status); + + /* handle some internal reason definitions. */ + if (MSG_IS_NOTIFY (request) && status == 481) + { + response->reason_phrase = osip_strdup ("Subcription Does Not Exist"); + } else if (MSG_IS_SUBSCRIBE (request) && status == 202) + { + response->reason_phrase = osip_strdup ("Accepted subscription"); + } else + { + response->reason_phrase = osip_strdup (osip_message_get_reason (status)); + if (response->reason_phrase == NULL) + { + if (response->status_code == 101) + response->reason_phrase = osip_strdup ("Dialog Establishement"); + else + response->reason_phrase = osip_strdup ("Unknown code"); + } + response->req_uri = NULL; + response->sip_method = NULL; + } + + i = osip_to_clone (request->to, &(response->to)); + if (i != 0) + goto grd_error_1; + + i = osip_to_get_tag (response->to, &tag); + if (i != 0) + { /* we only add a tag if it does not already contains one! */ + if ((dialog != NULL) && (dialog->local_tag != NULL)) + /* it should contain the local TAG we created */ + { + osip_to_set_tag (response->to, osip_strdup (dialog->local_tag)); + } else + { + if (status != 100) + osip_to_set_tag (response->to, osip_to_tag_new_random ()); + } + } + + i = osip_from_clone (request->from, &(response->from)); + if (i != 0) + goto grd_error_1; + + pos = 0; + while (!osip_list_eol (request->vias, pos)) + { + osip_via_t *via; + osip_via_t *via2; + + via = (osip_via_t *) osip_list_get (request->vias, pos); + i = osip_via_clone (via, &via2); + if (i != -0) + goto grd_error_1; + osip_list_add (response->vias, via2, -1); + pos++; + } + + i = osip_call_id_clone (request->call_id, &(response->call_id)); + if (i != 0) + goto grd_error_1; + i = osip_cseq_clone (request->cseq, &(response->cseq)); + if (i != 0) + goto grd_error_1; + + if (MSG_IS_SUBSCRIBE (request)) + { + osip_header_t *exp; + osip_header_t *evt_hdr; + + osip_message_header_get_byname (request, "event", 0, &evt_hdr); + if (evt_hdr != NULL && evt_hdr->hvalue != NULL) + osip_message_set_header (response, "Event", evt_hdr->hvalue); + else + osip_message_set_header (response, "Event", "presence"); + i = osip_message_get_expires (request, 0, &exp); + if (exp == NULL) + { + osip_header_t *cp; + + i = osip_header_clone (exp, &cp); + if (cp != NULL) + osip_list_add (response->headers, cp, 0); + } + } + + osip_message_set_allow (response, "INVITE"); + osip_message_set_allow (response, "ACK"); + osip_message_set_allow (response, "OPTIONS"); + osip_message_set_allow (response, "CANCEL"); + osip_message_set_allow (response, "BYE"); + osip_message_set_allow (response, "SUBSCRIBE"); + osip_message_set_allow (response, "NOTIFY"); + osip_message_set_allow (response, "MESSAGE"); + osip_message_set_allow (response, "INFO"); + osip_message_set_allow (response, "REFER"); + osip_message_set_allow (response, "UPDATE"); + + *dest = response; + return 0; + +grd_error_1: + osip_message_free (response); + return -1; +} + +int +complete_answer_that_establish_a_dialog (osip_message_t * response, + osip_message_t * request) +{ + int i; + int pos = 0; + char contact[1000]; + char locip[50]; + struct eXosip_net *net; + /* 12.1.1: + copy all record-route in response + add a contact with global scope + */ + while (!osip_list_eol (request->record_routes, pos)) + { + osip_record_route_t *rr; + osip_record_route_t *rr2; + + rr = osip_list_get (request->record_routes, pos); + i = osip_record_route_clone (rr, &rr2); + if (i != 0) + return -1; + osip_list_add (response->record_routes, rr2, -1); + pos++; + } + + i = _eXosip_find_protocol(response); + if (i==IPPROTO_UDP) + { + net = &eXosip.net_interfaces[0]; + } + else if (i==IPPROTO_TCP) + { + net = &eXosip.net_interfaces[1]; + } + else + { + net = &eXosip.net_interfaces[0]; + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: unsupported protocol (default to UDP)\n")); + return -1; + } + +#ifdef SM + eXosip_get_localip_from_via (response, locip, 49); +#else + eXosip_guess_ip_for_via (net->net_ip_family, locip, 49); +#endif + + if (request->to->url->username == NULL) + snprintf (contact, 1000, "<sip:%s:%s>", locip, net->net_port); + else + snprintf (contact, 1000, "<sip:%s@%s:%s>", request->to->url->username, + locip, net->net_port); + + if (eXosip.net_interfaces[0].net_firewall_ip[0] != '\0') + { + osip_contact_t *con = + (osip_contact_t *) osip_list_get (request->contacts, 0); + if (con != NULL && con->url != NULL && con->url->host != NULL) + { + char *c_address = con->url->host; + + struct addrinfo *addrinfo; + struct __eXosip_sockaddr addr; + i = eXosip_get_addrinfo (&addrinfo, con->url->host, 5060, IPPROTO_UDP); + if (i == 0) + { + memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + freeaddrinfo (addrinfo); + c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: here is the resolved destination host=%s\n", + c_address)); + } + + /* If c_address is a PUBLIC address, the request was + coming from the PUBLIC network. */ + if (eXosip_is_public_address (c_address)) + { + if (request->to->url->username == NULL) + snprintf (contact, 1000, "<sip:%s:%s>", + eXosip.net_interfaces[0].net_firewall_ip, + net->net_port); + else + snprintf (contact, 1000, "<sip:%s@%s:%s>", + request->to->url->username, + eXosip.net_interfaces[0].net_firewall_ip, + net->net_port); + } + } + } + + osip_message_set_contact (response, contact); + + return 0; +} + +int +_eXosip_answer_invite_1xx (eXosip_call_t * jc, eXosip_dialog_t * jd, int code, + osip_message_t ** answer) +{ + int i; + osip_transaction_t *tr; + + *answer = NULL; + tr = eXosip_find_last_inc_invite (jc, jd); + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state == IST_COMPLETED + || tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + if (jd == NULL) + i = _eXosip_build_response_default (answer, NULL, code, tr->orig_request); + else + i = + _eXosip_build_response_default (answer, jd->d_dialog, code, + tr->orig_request); + + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: Could not create response for invite\n")); + return -2; + } + + osip_message_set_content_length (*answer, "0"); + /* send message to transaction layer */ + + if (code > 100) + { + i = complete_answer_that_establish_a_dialog (*answer, tr->orig_request); + } + + return 0; +} + +int +_eXosip_answer_invite_2xx (eXosip_call_t * jc, eXosip_dialog_t * jd, int code, + osip_message_t ** answer) +{ + int i; + osip_transaction_t *tr; + + *answer = NULL; + tr = eXosip_find_last_inc_invite (jc, jd); + + if (tr == NULL || tr->orig_request == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer\n")); + return -1; + } + + if (jd != NULL && jd->d_dialog == NULL) + { /* element previously removed */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot answer this closed transaction\n")); + return -1; + } + + /* is the transaction already answered? */ + if (tr->state == IST_COMPLETED + || tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + if (jd == NULL) + i = _eXosip_build_response_default (answer, NULL, code, tr->orig_request); + else + i = + _eXosip_build_response_default (answer, jd->d_dialog, code, + tr->orig_request); + + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "ERROR: Could not create response for invite\n")); + return -1; + } + + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + { + i = complete_answer_that_establish_a_dialog (*answer, tr->orig_request); + if (i != 0) + goto g2atii_error_1;; /* ?? */ + } + + return 0; + +g2atii_error_1: + osip_message_free (*answer); + return -1; +} + +int +_eXosip_answer_invite_3456xx (eXosip_call_t * jc, eXosip_dialog_t * jd, + int code, osip_message_t ** answer) +{ + int i; + osip_transaction_t *tr; + + *answer = NULL; + tr = eXosip_find_last_inc_invite (jc, jd); + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state == IST_COMPLETED + || tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + i = + _eXosip_build_response_default (answer, jd->d_dialog, code, tr->orig_request); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "ERROR: Could not create response for invite\n")); + return -1; + } + + if ((300 <= code) && (code <= 399)) + { + /* Should add contact fields */ + /* ... */ + } + + osip_message_set_content_length (*answer, "0"); + /* send message to transaction layer */ + + return 0; +} + +int +_eXosip_default_answer_invite_1xx (eXosip_call_t * jc, eXosip_dialog_t * jd, + int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + + tr = eXosip_find_last_inc_invite (jc, jd); + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state == IST_COMPLETED + || tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + if (jd == NULL) + i = _eXosip_build_response_default (&response, NULL, code, tr->orig_request); + else + i = + _eXosip_build_response_default (&response, jd->d_dialog, code, + tr->orig_request); + + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: Could not create response for invite\n")); + return -2; + } + + osip_message_set_content_length (response, "0"); + /* send message to transaction layer */ + + if (code > 100) + { + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + i = complete_answer_that_establish_a_dialog (response, tr->orig_request); + + if (jd == NULL) + { + i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, response); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + } else + { + ADD_ELEMENT (jc->c_dialogs, jd); + } + } + } + + evt_answer = osip_new_outgoing_sipmessage (response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + __eXosip_wakeup (); + + return 0; +} + +int +_eXosip_default_answer_invite_3456xx (eXosip_call_t * jc, + eXosip_dialog_t * jd, int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + + tr = eXosip_find_last_inc_invite (jc, jd); + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + /* is the transaction already answered? */ + if (tr->state == IST_COMPLETED + || tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: transaction already answered\n")); + return -1; + } + + i = + _eXosip_build_response_default (&response, jd->d_dialog, code, + tr->orig_request); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "ERROR: Could not create response for invite\n")); + return -1; + } + + osip_message_set_content_length (response, "0"); + /* send message to transaction layer */ + + evt_answer = osip_new_outgoing_sipmessage (response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + __eXosip_wakeup (); + return 0; +} + + +int +_eXosip_insubscription_answer_1xx (eXosip_notify_t * jn, eXosip_dialog_t * jd, + int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + + tr = eXosip_find_last_inc_subscribe (jn, jd); + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + + if (jd == NULL) + i = _eXosip_build_response_default (&response, NULL, code, tr->orig_request); + else + i = + _eXosip_build_response_default (&response, jd->d_dialog, code, + tr->orig_request); + + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: Could not create response for subscribe\n")); + return -1; + } + + if (code > 100) + { + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + i = complete_answer_that_establish_a_dialog (response, tr->orig_request); + + if (jd == NULL) + { + i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, response); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + } + ADD_ELEMENT (jn->n_dialogs, jd); + } + } + + evt_answer = osip_new_outgoing_sipmessage (response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + __eXosip_wakeup (); + return 0; +} + +int +_eXosip_insubscription_answer_2xx (eXosip_notify_t * jn, eXosip_dialog_t * jd, + int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + + tr = eXosip_find_last_inc_subscribe (jn, jd); + + if (tr == NULL || tr->orig_request == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer\n")); + return -1; + } + + if (jd != NULL && jd->d_dialog == NULL) + { /* element previously removed, this is a no hop! */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot answer this closed transaction\n")); + return -1; + } + + if (jd == NULL) + i = _eXosip_build_response_default (&response, NULL, code, tr->orig_request); + else + i = + _eXosip_build_response_default (&response, jd->d_dialog, code, + tr->orig_request); + + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "ERROR: Could not create response for subscribe\n")); + code = 500; /* ? which code to use? */ + return -1; + } + + /* request that estabish a dialog: */ + /* 12.1.1 UAS Behavior */ + { + i = complete_answer_that_establish_a_dialog (response, tr->orig_request); + if (i != 0) + goto g2atii_error_1;; /* ?? */ + } + + /* THIS RESPONSE MUST BE SENT RELIABILY until the final ACK is received !! */ + /* this response must be stored at the upper layer!!! (it will be destroyed */ + /* right after being sent! */ + + if (jd == NULL) + { + i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, response); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + return -1; + } + ADD_ELEMENT (jn->n_dialogs, jd); + } + + eXosip_dialog_set_200ok (jd, response); + evt_answer = osip_new_outgoing_sipmessage (response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + __eXosip_wakeup (); + + osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED); + return 0; + +g2atii_error_1: + osip_message_free (response); + return -1; +} + +int +_eXosip_insubscription_answer_3456xx (eXosip_notify_t * jn, + eXosip_dialog_t * jd, int code) +{ + osip_event_t *evt_answer; + osip_message_t *response; + int i; + osip_transaction_t *tr; + + tr = eXosip_find_last_inc_subscribe (jn, jd); + if (tr == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot find transaction to answer")); + return -1; + } + if (jd == NULL) + i = _eXosip_build_response_default (&response, NULL, code, tr->orig_request); + else + i = + _eXosip_build_response_default (&response, jd->d_dialog, code, + tr->orig_request); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "ERROR: Could not create response for subscribe\n")); + return -1; + } + + if ((300 <= code) && (code <= 399)) + { + /* Should add contact fields */ + /* ... */ + } + + evt_answer = osip_new_outgoing_sipmessage (response); + evt_answer->transactionid = tr->transactionid; + + osip_transaction_add_event (tr, evt_answer); + __eXosip_wakeup (); + return 0; +} diff --git a/exosip2/jsubscribe.c b/exosip2/jsubscribe.c new file mode 100644 index 0000000000000000000000000000000000000000..7f58c793673d134522a715dd58bc7fa49642c4ce --- /dev/null +++ b/exosip2/jsubscribe.c @@ -0,0 +1,150 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +osip_transaction_t * +eXosip_find_last_out_subscribe (eXosip_subscribe_t * js, eXosip_dialog_t * jd) +{ + osip_transaction_t *out_tr; + int pos; + + out_tr = NULL; + pos = 0; + if (jd != NULL) + { + while (!osip_list_eol (jd->d_out_trs, pos)) + { + out_tr = osip_list_get (jd->d_out_trs, pos); + if (0 == strcmp (out_tr->cseq->method, "SUBSCRIBE")) + break; + else + out_tr = NULL; + pos++; + } + } else + out_tr = NULL; + + if (out_tr == NULL) + return js->s_out_tr; /* can be NULL */ + + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_inc_notify (eXosip_subscribe_t * js, eXosip_dialog_t * jd) +{ + osip_transaction_t *out_tr; + int pos; + + out_tr = NULL; + pos = 0; + if (jd != NULL) + { + while (!osip_list_eol (jd->d_out_trs, pos)) + { + out_tr = osip_list_get (jd->d_out_trs, pos); + if (0 == strcmp (out_tr->cseq->method, "NOTIFY")) + return out_tr; + pos++; + } + } + + return NULL; +} + + +int +eXosip_subscribe_init (eXosip_subscribe_t ** js) +{ + *js = (eXosip_subscribe_t *) osip_malloc (sizeof (eXosip_subscribe_t)); + if (*js == NULL) + return -1; + memset (*js, 0, sizeof (eXosip_subscribe_t)); + return 0; +} + +void +eXosip_subscribe_free (eXosip_subscribe_t * js) +{ + /* ... */ + + eXosip_dialog_t *jd; + + for (jd = js->s_dialogs; jd != NULL; jd = js->s_dialogs) + { + REMOVE_ELEMENT (js->s_dialogs, jd); + eXosip_dialog_free (jd); + } + + __eXosip_delete_jinfo (js->s_inc_tr); + __eXosip_delete_jinfo (js->s_out_tr); + if (js->s_inc_tr != NULL) + osip_list_add (eXosip.j_transactions, js->s_inc_tr, 0); + if (js->s_out_tr != NULL) + osip_list_add (eXosip.j_transactions, js->s_out_tr, 0); + + osip_free (js); +} + +int +_eXosip_subscribe_set_refresh_interval (eXosip_subscribe_t * js, + osip_message_t * out_subscribe) +{ + osip_header_t *exp; + + if (js == NULL || out_subscribe == NULL) + return -1; + + osip_message_get_expires (out_subscribe, 0, &exp); + if (exp == NULL || exp->hvalue == NULL) + js->s_reg_period = 3600; + else + { + js->s_reg_period = osip_atoi (exp->hvalue); + if (js->s_reg_period < 0) + js->s_reg_period = 3600; + } + + return 0; +} + +int +eXosip_subscribe_need_refresh (eXosip_subscribe_t * js, eXosip_dialog_t * jd, + int now) +{ + osip_transaction_t *out_tr = NULL; + + if (jd != NULL) + out_tr = osip_list_get (jd->d_out_trs, 0); + if (out_tr == NULL) + out_tr = js->s_out_tr; + + if (now - out_tr->birth_time > js->s_reg_period - 60) + return 0; + return -1; +} diff --git a/exosip2/misc.c b/exosip2/misc.c new file mode 100644 index 0000000000000000000000000000000000000000..b811c4764d9d8a28effff24848d65addf3877770 --- /dev/null +++ b/exosip2/misc.c @@ -0,0 +1,239 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + + +#include "eXosip2.h" + +extern eXosip_t eXosip; + + +/* some methods to extract transaction information from a eXosip_call_t */ + +int +eXosip_remove_transaction_from_call (osip_transaction_t * tr, eXosip_call_t * jc) +{ + osip_transaction_t *inc_tr; + osip_transaction_t *out_tr; + eXosip_dialog_t *jd; + int pos = 0; + + if (jc->c_inc_tr == tr) + { + jc->c_inc_tr = NULL; /* can be NULL */ + return 0; + } + + for (jd = jc->c_dialogs; jd != NULL; jd = jd->next) + { + pos = 0; + while (!osip_list_eol (jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get (jd->d_inc_trs, pos); + if (inc_tr == tr) + { + osip_list_remove (jd->d_inc_trs, pos); + return 0; + } + pos++; + } + } + + if (jc->c_out_tr == tr) + { + jc->c_out_tr = NULL; /* can be NULL */ + return 0; + } + + for (jd = jc->c_dialogs; jd != NULL; jd = jd->next) + { + pos = 0; + while (!osip_list_eol (jd->d_out_trs, pos)) + { + out_tr = osip_list_get (jd->d_out_trs, pos); + if (out_tr == tr) + { + osip_list_remove (jd->d_out_trs, pos); + return 0; + } + pos++; + } + } + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: No information.\n")); + return -1; +} + +osip_transaction_t * +eXosip_find_last_transaction (eXosip_call_t * jc, eXosip_dialog_t * jd, + const char *method) +{ + osip_transaction_t *inc_tr; + osip_transaction_t *out_tr; + + inc_tr = eXosip_find_last_inc_transaction (jc, jd, method); + out_tr = eXosip_find_last_out_transaction (jc, jd, method); + if (inc_tr == NULL) + return out_tr; + if (out_tr == NULL) + return inc_tr; + + if (inc_tr->birth_time > out_tr->birth_time) + return inc_tr; + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_inc_transaction (eXosip_call_t * jc, eXosip_dialog_t * jd, + const char *method) +{ + osip_transaction_t *inc_tr; + int pos; + + inc_tr = NULL; + pos = 0; + if (method == NULL || method[0] == '\0') + return NULL; + if (jd != NULL) + { + while (!osip_list_eol (jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get (jd->d_inc_trs, pos); + if (0 == osip_strcasecmp (inc_tr->cseq->method, method)) + break; + else + inc_tr = NULL; + pos++; + } + } else + inc_tr = NULL; + + return inc_tr; +} + +osip_transaction_t * +eXosip_find_last_out_transaction (eXosip_call_t * jc, eXosip_dialog_t * jd, + const char *method) +{ + osip_transaction_t *out_tr; + int pos; + + out_tr = NULL; + pos = 0; + if (jd == NULL && jc == NULL) + return NULL; + if (method == NULL || method[0] == '\0') + return NULL; + + if (jd != NULL) + { + while (!osip_list_eol (jd->d_out_trs, pos)) + { + out_tr = osip_list_get (jd->d_out_trs, pos); + if (0 == osip_strcasecmp (out_tr->cseq->method, method)) + break; + else + out_tr = NULL; + pos++; + } + } + + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_invite (eXosip_call_t * jc, eXosip_dialog_t * jd) +{ + osip_transaction_t *inc_tr; + osip_transaction_t *out_tr; + + inc_tr = eXosip_find_last_inc_invite (jc, jd); + out_tr = eXosip_find_last_out_invite (jc, jd); + if (inc_tr == NULL) + return out_tr; + if (out_tr == NULL) + return inc_tr; + + if (inc_tr->birth_time > out_tr->birth_time) + return inc_tr; + return out_tr; +} + +osip_transaction_t * +eXosip_find_last_inc_invite (eXosip_call_t * jc, eXosip_dialog_t * jd) +{ + osip_transaction_t *inc_tr; + int pos; + + inc_tr = NULL; + pos = 0; + if (jd != NULL) + { + while (!osip_list_eol (jd->d_inc_trs, pos)) + { + inc_tr = osip_list_get (jd->d_inc_trs, pos); + if (0 == strcmp (inc_tr->cseq->method, "INVITE")) + break; + else + inc_tr = NULL; + pos++; + } + } else + inc_tr = NULL; + + if (inc_tr == NULL) + return jc->c_inc_tr; /* can be NULL */ + + return inc_tr; +} + +osip_transaction_t * +eXosip_find_last_out_invite (eXosip_call_t * jc, eXosip_dialog_t * jd) +{ + osip_transaction_t *out_tr; + int pos; + + out_tr = NULL; + pos = 0; + if (jd == NULL && jc == NULL) + return NULL; + + if (jd != NULL) + { + while (!osip_list_eol (jd->d_out_trs, pos)) + { + out_tr = osip_list_get (jd->d_out_trs, pos); + if (0 == strcmp (out_tr->cseq->method, "INVITE")) + break; + else + out_tr = NULL; + pos++; + } + } + + if (out_tr == NULL) + return jc->c_out_tr; /* can be NULL */ + + return out_tr; +} diff --git a/exosip2/sdp_offans.c b/exosip2/sdp_offans.c new file mode 100644 index 0000000000000000000000000000000000000000..0d30fdcc1935931f3458e1b50a2d5c2f1902b5f0 --- /dev/null +++ b/exosip2/sdp_offans.c @@ -0,0 +1,204 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" + +extern eXosip_t eXosip; + +sdp_message_t *_eXosip_get_remote_sdp (osip_transaction_t * invite_tr); +sdp_message_t *_eXosip_get_local_sdp (osip_transaction_t * invite_tr); + + +sdp_message_t * +eXosip_get_remote_sdp (int jid) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + osip_transaction_t *invite_tr = NULL; + + if (jid > 0) + { + eXosip_call_dialog_find (jid, &jc, &jd); + } + if (jc == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return NULL; + } + invite_tr = eXosip_find_last_invite (jc, jd); + if (invite_tr == NULL) + return NULL; + + return _eXosip_get_remote_sdp (invite_tr); +} + +sdp_message_t * +eXosip_get_local_sdp (int jid) +{ + eXosip_dialog_t *jd = NULL; + eXosip_call_t *jc = NULL; + osip_transaction_t *invite_tr = NULL; + + if (jid > 0) + { + eXosip_call_dialog_find (jid, &jc, &jd); + } + if (jc == NULL) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: No call here?\n")); + return NULL; + } + invite_tr = eXosip_find_last_invite (jc, jd); + if (invite_tr == NULL) + return NULL; + + return _eXosip_get_local_sdp (invite_tr); +} + +sdp_message_t * +_eXosip_get_remote_sdp (osip_transaction_t * invite_tr) +{ + osip_message_t *message; + + if (invite_tr == NULL) + return NULL; + if (invite_tr->ctx_type == IST) + message = invite_tr->orig_request; + else if (invite_tr->ctx_type == ICT) + message = invite_tr->last_response; + else + return NULL; + return eXosip_get_sdp_info (message); +} + +sdp_message_t * +_eXosip_get_local_sdp (osip_transaction_t * invite_tr) +{ + osip_message_t *message; + + if (invite_tr == NULL) + return NULL; + if (invite_tr->ctx_type == IST) + message = invite_tr->last_response; + else if (invite_tr->ctx_type == ICT) + message = invite_tr->orig_request; + else + return NULL; + return eXosip_get_sdp_info (message); +} + +sdp_message_t * +eXosip_get_sdp_info (osip_message_t * message) +{ + osip_content_type_t *ctt; + osip_mime_version_t *mv; + sdp_message_t *sdp; + osip_body_t *oldbody; + int pos; + + if (message == NULL) + return NULL; + + /* get content-type info */ + ctt = osip_message_get_content_type (message); + mv = osip_message_get_mime_version (message); + if (mv == NULL && ctt == NULL) + return NULL; /* previous message was not correct or empty */ + if (mv != NULL) + { + /* look for the SDP body */ + /* ... */ + } else if (ctt != NULL) + { + if (ctt->type == NULL || ctt->subtype == NULL) + /* it can be application/sdp or mime... */ + return NULL; + if (osip_strcasecmp (ctt->type, "application") != 0 || + osip_strcasecmp (ctt->subtype, "sdp") != 0) + { + return NULL; + } + } + + pos = 0; + while (!osip_list_eol (message->bodies, pos)) + { + int i; + + oldbody = (osip_body_t *) osip_list_get (message->bodies, pos); + pos++; + sdp_message_init (&sdp); + i = sdp_message_parse (sdp, oldbody->body); + if (i == 0) + return sdp; + sdp_message_free (sdp); + sdp = NULL; + } + return NULL; +} + + +sdp_connection_t * +eXosip_get_audio_connection (sdp_message_t * sdp) +{ + int pos = 0; + sdp_media_t *med = (sdp_media_t *) osip_list_get (sdp->m_medias, 0); + + while (med != NULL) + { + if (med->m_media != NULL && osip_strcasecmp (med->m_media, "audio") == 0) + break; + pos++; + med = (sdp_media_t *) osip_list_get (sdp->m_medias, pos); + } + if (med == NULL) + return NULL; /* no audio stream */ + if (osip_list_eol (med->c_connections, 0)) + return sdp->c_connection; + + /* just return the first one... */ + return (sdp_connection_t *) osip_list_get (med->c_connections, 0); +} + + +sdp_media_t * +eXosip_get_audio_media (sdp_message_t * sdp) +{ + int pos = 0; + sdp_media_t *med = (sdp_media_t *) osip_list_get (sdp->m_medias, 0); + + while (med != NULL) + { + if (med->m_media != NULL && osip_strcasecmp (med->m_media, "audio") == 0) + return med; + pos++; + med = (sdp_media_t *) osip_list_get (sdp->m_medias, pos); + } + + return NULL; +} diff --git a/exosip2/udp.c b/exosip2/udp.c new file mode 100644 index 0000000000000000000000000000000000000000..f70b12daa7198fd8ed5d54a2cd75f21d8df05db5 --- /dev/null +++ b/exosip2/udp.c @@ -0,0 +1,2307 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#include "eXosip2.h" +#include <eXosip2/eXosip.h> + +#ifndef WIN32 +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#ifdef __APPLE_CC__ +#include <unistd.h> +#endif +#else +#include <windows.h> +#endif + +extern eXosip_t eXosip; +extern int ipv6_enable; + +/* Private functions */ +static void eXosip_send_default_answer (eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt, + int status, + char *reason_phrase, + char *warning, int line); +static void eXosip_process_info (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt); +static void eXosip_process_options (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt); +static void eXosip_process_bye (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt); +static void eXosip_process_refer (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt); +static void eXosip_process_ack (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_event_t * evt); +static void eXosip_process_prack (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt); +static int cancel_match_invite (osip_transaction_t * invite, + osip_message_t * cancel); +static void eXosip_process_cancel (osip_transaction_t * transaction, + osip_event_t * evt); +static osip_event_t *eXosip_process_reinvite (eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_transaction_t * + transaction, osip_event_t * evt); +static void eXosip_process_new_options (osip_transaction_t * transaction, + osip_event_t * evt); +static void eXosip_process_new_invite (osip_transaction_t * transaction, + osip_event_t * evt); +static int eXosip_event_package_is_supported (osip_transaction_t * + transaction, osip_event_t * evt); +static void eXosip_process_new_subscribe (osip_transaction_t * transaction, + osip_event_t * evt); +static void eXosip_process_subscribe_within_call (eXosip_notify_t * jn, + eXosip_dialog_t * jd, + osip_transaction_t * + transaction, osip_event_t * evt); +static void eXosip_process_notify_within_dialog (eXosip_subscribe_t * js, + eXosip_dialog_t * jd, + osip_transaction_t * + transaction, osip_event_t * evt); +static int eXosip_match_notify_for_subscribe (eXosip_subscribe_t * js, + osip_message_t * notify); +static void eXosip_process_message_outside_of_dialog (osip_transaction_t * tr, + osip_event_t * evt); +static void eXosip_process_refer_outside_of_dialog (osip_transaction_t * tr, + osip_event_t * evt); +static void eXosip_process_message_within_dialog (eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt); +static void eXosip_process_newrequest (osip_event_t * evt, int socket); +static void eXosip_process_response_out_of_transaction (osip_event_t * evt); +static int eXosip_pendingosip_transaction_exist (eXosip_call_t * jc, + eXosip_dialog_t * jd); +static int eXosip_release_finished_calls (eXosip_call_t * jc, + eXosip_dialog_t * jd); +static int eXosip_release_aborted_calls (eXosip_call_t * jc, eXosip_dialog_t * jd); + + +static void +eXosip_send_default_answer (eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt, + int status, + char *reason_phrase, char *warning, int line) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + /* osip_list_add(eXosip.j_transactions, transaction, 0); */ + osip_transaction_set_your_instance (transaction, NULL); + + /* THIS METHOD DOES NOT ACCEPT STATUS CODE BETWEEN 101 and 299 */ + if (status > 100 && status < 299 && MSG_IS_INVITE (evt->sip)) + return; + + if (jd != NULL) + i = _eXosip_build_response_default (&answer, jd->d_dialog, status, evt->sip); + else + i = _eXosip_build_response_default (&answer, NULL, status, evt->sip); + + if (i != 0 || answer == NULL) + { + return; + } + + if (reason_phrase != NULL) + { + char *_reason; + + _reason = osip_message_get_reason_phrase (answer); + if (_reason != NULL) + osip_free (_reason); + _reason = osip_strdup (reason_phrase); + osip_message_set_reason_phrase (answer, _reason); + } + + osip_message_set_content_length (answer, "0"); + + if (status == 500) + osip_message_set_retry_after (answer, "10"); + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event (transaction, evt_answer); + __eXosip_wakeup (); + +} + +static void +eXosip_process_options (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_list_add (jd->d_inc_trs, transaction, 0); + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + __eXosip_wakeup (); +} + +static void +eXosip_process_info (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_list_add (jd->d_inc_trs, transaction, 0); + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + __eXosip_wakeup (); +} + + +static void +eXosip_process_bye (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, NULL /*jd */ , + NULL, NULL)); + + i = _eXosip_build_response_default (&answer, jd->d_dialog, 200, evt->sip); + if (i != 0) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + return; + } + osip_message_set_content_length (answer, "0"); + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + + osip_list_add (jd->d_inc_trs, transaction, 0); + + /* Release the eXosip_dialog */ + osip_dialog_free (jd->d_dialog); + jd->d_dialog = NULL; + report_call_event (EXOSIP_CALL_CLOSED, jc, jd, transaction); + eXosip_update(); /* AMD 30/09/05 */ + + osip_transaction_add_event (transaction, evt_answer); + __eXosip_wakeup (); +} + +static void +eXosip_process_refer (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_header_t *referto_head = NULL; + osip_contact_t *referto; + int i; + + /* check if the refer is valid */ + osip_message_header_get_byname (evt->sip, "refer-to", 0, &referto_head); + if (referto_head == NULL || referto_head->hvalue == NULL) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 400, + "Missing Refer-To header", + "Missing Refer-To header", __LINE__); + return; + } + /* check if refer-to is well-formed */ + osip_contact_init (&referto); + i = osip_contact_parse (referto, referto_head->hvalue); + if (i != 0) + { + osip_contact_free (referto); + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 400, + "Non valid Refer-To header", + "Non valid Refer-To header", __LINE__); + return; + } + + osip_contact_free (referto); + + /* check policy so we can decline immediatly the refer */ + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + osip_list_add (jd->d_inc_trs, transaction, 0); + __eXosip_wakeup (); +} + +static void +eXosip_process_notify_for_refer (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + osip_transaction_t *ref; + osip_header_t *event_hdr; + osip_header_t *sub_state; + osip_content_type_t *ctype; + osip_body_t *body = NULL; + + /* get the event type and return "489 Bad Event". */ + osip_message_header_get_byname (evt->sip, "event", 0, &event_hdr); + if (event_hdr == NULL || event_hdr->hvalue == NULL) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 400, + "Missing Event header in Notify", + "Missing Event header in Notify", __LINE__); + return; + } + if (NULL==strstr(event_hdr->hvalue, "refer")) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 501, + "Unsupported Event header", + "Unsupported Event header in Notify", __LINE__); + return; + } + osip_message_header_get_byname (evt->sip, "subscription-state", 0, &sub_state); + if (sub_state == NULL || sub_state->hvalue == NULL) + { +#ifndef CISCO_BUG + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 400, "Missing Header", + "Missing subscription-state Header", __LINE__); + return; +#else + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_WARNING, NULL, + "eXosip: Missing subscription-state Header (cisco 7960 bug)\n")); +#endif + } + + ctype = osip_message_get_content_type (evt->sip); + if (ctype == NULL || ctype->type == NULL || ctype->subtype == NULL) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 400, "Missing Header", + "Missing Content-Type Header", __LINE__); + return; + } + if (0 != osip_strcasecmp (ctype->type, "message") + || 0 != osip_strcasecmp (ctype->subtype, "sipfrag")) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 501, + "Unsupported body type", + "Unsupported body type", __LINE__); + return; + } + + osip_message_get_body (evt->sip, 0, &body); + if (body == NULL || body->body == NULL) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 400, "Missing Body", + "Missing Body", __LINE__); + return; + } + +#if 0 + report_call_event (EXOSIP_CALL_REFER_STATUS, jc, jd, transaction); +#endif + + /* check if a refer was sent previously! */ + ref = eXosip_find_last_out_transaction (jc, jd, "REFER"); + if (ref == NULL) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 481, NULL, + "No associated refer", __LINE__); + return; + } + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + /* for now, send default response of 200ok. eventually, application should + be deciding how to answer NOTIFY messages */ + i = _eXosip_build_response_default (&answer, jd->d_dialog, 200, evt->sip); + if (i != 0) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + return; + } + + i = complete_answer_that_establish_a_dialog (answer, evt->sip); + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + + osip_list_add (jd->d_inc_trs, transaction, 0); + + osip_transaction_add_event (transaction, evt_answer); + __eXosip_wakeup (); +} + +static void +eXosip_process_ack (eXosip_call_t * jc, eXosip_dialog_t * jd, osip_event_t * evt) +{ + /* TODO: We should find the matching transaction for this ACK + and also add the ACK in the event. */ + eXosip_event_t *je; + int i; + + je = eXosip_event_init_for_call (EXOSIP_CALL_ACK, jc, jd, NULL); + if (je!=NULL) + { + i = osip_message_clone (evt->sip, &je->ack); + if (i != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "failed to clone ACK for event\n")); + } + else + report_event (je, NULL); + } + + osip_event_free (evt); +} + +static void +eXosip_process_prack (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + i = _eXosip_build_response_default (&answer, jd->d_dialog, 200, evt->sip); + if (i != 0) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + return; + } + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + + osip_list_add (jd->d_inc_trs, transaction, 0); + + osip_transaction_add_event (transaction, evt_answer); + __eXosip_wakeup (); +} + +static int +cancel_match_invite (osip_transaction_t * invite, osip_message_t * cancel) +{ + osip_generic_param_t *br; + osip_generic_param_t *br2; + osip_via_t *via; + + osip_via_param_get_byname (invite->topvia, "branch", &br); + via = osip_list_get (cancel->vias, 0); + if (via == NULL) + return -1; /* request without via??? */ + osip_via_param_get_byname (via, "branch", &br2); + if (br != NULL && br2 == NULL) + return -1; + if (br2 != NULL && br == NULL) + return -1; + if (br2 != NULL && br != NULL) /* compliant UA :) */ + { + if (br->gvalue != NULL && br2->gvalue != NULL && + 0 == strcmp (br->gvalue, br2->gvalue)) + return 0; + return -1; + } + /* old backward compatibility mechanism */ + if (0 != osip_call_id_match (invite->callid, cancel->call_id)) + return -1; + if (0 != osip_to_tag_match (invite->to, cancel->to)) + return -1; + if (0 != osip_from_tag_match (invite->from, cancel->from)) + return -1; + if (0 != osip_via_match (invite->topvia, via)) + return -1; + return 0; +} + +static void +eXosip_process_cancel (osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_transaction_t *tr; + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + + eXosip_call_t *jc; + eXosip_dialog_t *jd; + + tr = NULL; + jd = NULL; + /* first, look for a Dialog in the map of element */ + for (jc = eXosip.j_calls; jc != NULL; jc = jc->next) + { + if (jc->c_inc_tr != NULL) + { + i = cancel_match_invite (jc->c_inc_tr, evt->sip); + if (i == 0) + { + tr = jc->c_inc_tr; + /* fixed */ + if (jc->c_dialogs!=NULL) + jd = jc->c_dialogs; + break; + } + } + tr = NULL; + for (jd = jc->c_dialogs; jd != NULL; jd = jd->next) + { + int pos = 0; + + while (!osip_list_eol (jd->d_inc_trs, pos)) + { + tr = osip_list_get (jd->d_inc_trs, pos); + i = cancel_match_invite (tr, evt->sip); + if (i == 0) + break; + tr = NULL; + pos++; + } + } + if (jd != NULL) + break; /* tr has just been found! */ + } + + if (tr == NULL) /* we didn't found the transaction to cancel */ + { + i = _eXosip_build_response_default (&answer, NULL, 481, evt->sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot cancel transaction.\n")); + osip_list_add (eXosip.j_transactions, tr, 0); + osip_transaction_set_your_instance (tr, NULL); + return; + } + osip_message_set_content_length (answer, "0"); + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event (transaction, evt_answer); + + osip_list_add (eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance (transaction, NULL); + __eXosip_wakeup (); + return; + } + + if (tr->state == IST_TERMINATED || tr->state == IST_CONFIRMED + || tr->state == IST_COMPLETED) + { + /* I can't find the status code in the rfc? + (I read I must answer 200? wich I found strange) + I probably misunderstood it... and prefer to send 481 + as the transaction has been answered. */ + if (jd == NULL) + i = _eXosip_build_response_default (&answer, NULL, 481, evt->sip); + else + i = _eXosip_build_response_default (&answer, jd->d_dialog, 481, evt->sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot cancel transaction.\n")); + osip_list_add (eXosip.j_transactions, tr, 0); + osip_transaction_set_your_instance (tr, NULL); + return; + } + osip_message_set_content_length (answer, "0"); + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event (transaction, evt_answer); + + if (jd != NULL) + osip_list_add (jd->d_inc_trs, transaction, 0); + else + osip_list_add (eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance (transaction, NULL); + __eXosip_wakeup (); + + return; + } + + { + if (jd == NULL) + i = _eXosip_build_response_default (&answer, NULL, 200, evt->sip); + else + i = _eXosip_build_response_default (&answer, jd->d_dialog, 200, evt->sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot cancel transaction.\n")); + osip_list_add (eXosip.j_transactions, tr, 0); + osip_transaction_set_your_instance (tr, NULL); + return; + } + osip_message_set_content_length (answer, "0"); + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event (transaction, evt_answer); + __eXosip_wakeup (); + + if (jd != NULL) + osip_list_add (jd->d_inc_trs, transaction, 0); + else + osip_list_add (eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance (transaction, NULL); + + /* answer transaction to cancel */ + if (jd == NULL) + i = _eXosip_build_response_default (&answer, NULL, 487, tr->orig_request); + else + i = _eXosip_build_response_default (&answer, jd->d_dialog, 487, + tr->orig_request); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot cancel transaction.\n")); + osip_list_add (eXosip.j_transactions, tr, 0); + osip_transaction_set_your_instance (tr, NULL); + return; + } + osip_message_set_content_length (answer, "0"); + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = tr->transactionid; + osip_transaction_add_event (tr, evt_answer); + __eXosip_wakeup (); + } +} + +static osip_event_t * +eXosip_process_reinvite (eXosip_call_t * jc, eXosip_dialog_t * jd, + osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_message_t *answer; + osip_event_t *sipevent; + int i; + + i = _eXosip_build_response_default (&answer, jd->d_dialog, 100, evt->sip); + if (i != 0) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 500, + "Internal SIP Error", + "Failed to build Answer for INVITE within call", + __LINE__); + return NULL; + } + + complete_answer_that_establish_a_dialog (answer, evt->sip); + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + sipevent = osip_new_outgoing_sipmessage (answer); + sipevent->transactionid = transaction->transactionid; + + osip_list_add (jd->d_inc_trs, transaction, 0); + + osip_ist_execute (eXosip.j_osip); + + report_call_event (EXOSIP_CALL_REINVITE, jc, jd, transaction); + return sipevent; +} + +static void +eXosip_process_new_options (osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_list_add (eXosip.j_transactions, transaction, 0); + __eXosip_wakeup (); /* needed? */ +} + +static void +eXosip_process_new_invite (osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_event_t *evt_answer; + int i; + eXosip_call_t *jc; + eXosip_dialog_t *jd; + osip_message_t *answer; + + eXosip_call_init (&jc); + + ADD_ELEMENT (eXosip.j_calls, jc); + + i = _eXosip_build_response_default (&answer, NULL, 101, evt->sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog.")); + osip_list_add (eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance (transaction, NULL); + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: Could not create response for invite\n")); + return; + } + osip_message_set_content_length (answer, "0"); + i = complete_answer_that_establish_a_dialog (answer, evt->sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot complete answer!\n")); + osip_list_add (eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance (transaction, NULL); + osip_message_free (answer); + return; + } + + i = eXosip_dialog_init_as_uas (&jd, evt->sip, answer); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + osip_list_add (eXosip.j_transactions, transaction, 0); + osip_transaction_set_your_instance (transaction, NULL); + osip_message_free (answer); + return; + } + ADD_ELEMENT (jc->c_dialogs, jd); + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + + eXosip_update (); + jc->c_inc_tr = transaction; + osip_transaction_add_event (transaction, evt_answer); + + /* be sure the invite will be processed + before any API call on this dialog */ + osip_ist_execute (eXosip.j_osip); + + if (transaction->orig_request != NULL) + { + report_call_event (EXOSIP_CALL_INVITE, jc, jd, transaction); + } + + __eXosip_wakeup (); + +} + +static int +eXosip_event_package_is_supported (osip_transaction_t * transaction, + osip_event_t * evt) +{ + osip_header_t *event_hdr; + int code; + + /* get the event type and return "489 Bad Event". */ + osip_message_header_get_byname (evt->sip, "event", 0, &event_hdr); + if (event_hdr == NULL || event_hdr->hvalue == NULL) + { +#ifdef SUPPORT_MSN + /* msn don't show any event header */ + code = 200; /* Bad Request... anyway... */ +#else + code = 400; /* Bad Request */ +#endif + } else if (0 != osip_strcasecmp (event_hdr->hvalue, "presence")) + code = 489; + else + code = 200; + if (code != 200) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (NULL, transaction, evt, code, NULL, NULL, + __LINE__); + return 0; + } + return -1; +} + +static void +eXosip_process_new_subscribe (osip_transaction_t * transaction, osip_event_t * evt) +{ + osip_event_t *evt_answer; + eXosip_notify_t *jn; + eXosip_dialog_t *jd; + osip_message_t *answer; + int i; + + eXosip_notify_init (&jn, evt->sip); + _eXosip_notify_set_refresh_interval (jn, evt->sip); + + i = _eXosip_build_response_default (&answer, NULL, 101, evt->sip); + if (i != 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "ERROR: Could not create response for invite\n")); + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_notify_free (jn); + return; + } + i = complete_answer_that_establish_a_dialog (answer, evt->sip); + if (i != 0) + { + osip_message_free (answer); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot complete answer!\n")); + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_notify_free (jn); + return; + } + + i = eXosip_dialog_init_as_uas (&jd, evt->sip, answer); + if (i != 0) + { + osip_message_free (answer); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot create dialog!\n")); + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_notify_free (jn); + return; + } + ADD_ELEMENT (jn->n_dialogs, jd); + + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, jd, NULL, jn)); + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + osip_transaction_add_event (transaction, evt_answer); + + ADD_ELEMENT (eXosip.j_notifies, jn); + __eXosip_wakeup (); + + jn->n_inc_tr = transaction; + + eXosip_update (); + __eXosip_wakeup (); +} + +static void +eXosip_process_subscribe_within_call (eXosip_notify_t * jn, + eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt) +{ + _eXosip_notify_set_refresh_interval (jn, evt->sip); + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, jd, NULL, jn)); + + /* if subscribe request contains expires="0", close the subscription */ + { + int now = time (NULL); + + if (jn->n_ss_expires - now <= 0) + { + jn->n_ss_status = EXOSIP_SUBCRSTATE_TERMINATED; + jn->n_ss_reason = TIMEOUT; + } + } + + osip_list_add (jd->d_inc_trs, transaction, 0); + __eXosip_wakeup (); + return; +} + +static void +eXosip_process_notify_within_dialog (eXosip_subscribe_t * js, + eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt) +{ + osip_message_t *answer; + osip_event_t *sipevent; + osip_header_t *sub_state; + +#ifdef SUPPORT_MSN + osip_header_t *expires; +#endif + int i; + + if (jd == NULL) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 500, + "Internal SIP Error", + "No dialog for this NOTIFY", __LINE__); + return; + } + + /* if subscription-state has a reason state set to terminated, + we close the dialog */ +#ifndef SUPPORT_MSN + osip_message_header_get_byname (evt->sip, "subscription-state", 0, &sub_state); + if (sub_state == NULL || sub_state->hvalue == NULL) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 400, NULL, NULL, __LINE__); + return; + } +#endif + + i = _eXosip_build_response_default (&answer, jd->d_dialog, 200, evt->sip); + if (i != 0) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 500, + "Internal SIP Error", + "Failed to build Answer for NOTIFY", __LINE__); + return; + } +#ifdef SUPPORT_MSN + osip_message_header_get_byname (evt->sip, "expires", 0, &expires); + if (expires != NULL && expires->hvalue != NULL + && 0 == osip_strcasecmp (expires->hvalue, "0")) + { + /* delete the dialog! */ + js->s_ss_status = EXOSIP_SUBCRSTATE_TERMINATED; + { + eXosip_event_t *je; + + je = eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_NOTIFY, js, jd); + eXosip_event_add (je); + } + + sipevent = osip_new_outgoing_sipmessage (answer); + sipevent->transactionid = transaction->transactionid; + osip_transaction_add_event (transaction, sipevent); + + osip_list_add (eXosip.j_transactions, transaction, 0); + + REMOVE_ELEMENT (eXosip.j_subscribes, js); + eXosip_subscribe_free (js); + __eXosip_wakeup (); + + return; + } else + { + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, jd, js, NULL)); + js->s_ss_status = EXOSIP_SUBCRSTATE_ACTIVE; + } +#else + /* modify the status of user */ + if (0 == osip_strncasecmp (sub_state->hvalue, "active", 6)) + { + js->s_ss_status = EXOSIP_SUBCRSTATE_ACTIVE; + } else if (0 == osip_strncasecmp (sub_state->hvalue, "pending", 7)) + { + js->s_ss_status = EXOSIP_SUBCRSTATE_PENDING; + } + + if (0 == osip_strncasecmp (sub_state->hvalue, "terminated", 10)) + { + /* delete the dialog! */ + js->s_ss_status = EXOSIP_SUBCRSTATE_TERMINATED; + + { + eXosip_event_t *je; + + je = + eXosip_event_init_for_subscribe (EXOSIP_SUBSCRIPTION_NOTIFY, js, jd, + transaction); + eXosip_event_add (je); + } + + sipevent = osip_new_outgoing_sipmessage (answer); + sipevent->transactionid = transaction->transactionid; + osip_transaction_add_event (transaction, sipevent); + + osip_list_add (eXosip.j_transactions, transaction, 0); + + REMOVE_ELEMENT (eXosip.j_subscribes, js); + eXosip_subscribe_free (js); + __eXosip_wakeup (); + return; + } else + { + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (NULL, jd, js, NULL)); + } +#endif + + osip_list_add (jd->d_inc_trs, transaction, 0); + + sipevent = osip_new_outgoing_sipmessage (answer); + sipevent->transactionid = transaction->transactionid; + osip_transaction_add_event (transaction, sipevent); + + __eXosip_wakeup (); + return; +} + +static int +eXosip_match_notify_for_subscribe (eXosip_subscribe_t * js, + osip_message_t * notify) +{ + osip_transaction_t *out_sub; + + if (js == NULL) + return -1; + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Trying to match notify with subscribe\n")); + + out_sub = eXosip_find_last_out_subscribe (js, NULL); + if (out_sub == NULL || out_sub->orig_request == NULL) + return -1; + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "subscribe transaction found\n")); + + /* some checks to avoid crashing on bad requests */ + if (notify == NULL || notify->cseq == NULL + || notify->cseq->method == NULL || notify->to == NULL) + return -1; + + if (0 != osip_call_id_match (out_sub->callid, notify->call_id)) + return -1; + + { + /* The From tag of outgoing request must match + the To tag of incoming notify: + */ + osip_generic_param_t *tag_from; + osip_generic_param_t *tag_to; + + osip_from_param_get_byname (out_sub->from, "tag", &tag_from); + osip_from_param_get_byname (notify->to, "tag", &tag_to); + if (tag_to == NULL || tag_to->gvalue == NULL) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Uncompliant user agent: no tag in from of outgoing request\n")); + return -1; + } + if (tag_from == NULL || tag_to->gvalue == NULL) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Uncompliant user agent: no tag in to of incoming request\n")); + return -1; + } + + if (0 != strcmp (tag_from->gvalue, tag_to->gvalue)) + return -1; + } + + return 0; +} + +static void +eXosip_process_message_outside_of_dialog (osip_transaction_t * transaction, + osip_event_t * evt) +{ + osip_list_add (eXosip.j_transactions, transaction, 0); + __eXosip_wakeup (); /* needed? */ + return; +} + +static void +eXosip_process_refer_outside_of_dialog (osip_transaction_t * transaction, + osip_event_t * evt) +{ + osip_list_add (eXosip.j_transactions, transaction, 0); + __eXosip_wakeup (); /* needed? */ + return; +} + +static void +eXosip_process_message_within_dialog (eXosip_call_t * jc, + eXosip_dialog_t * jd, + osip_transaction_t * transaction, + osip_event_t * evt) +{ + osip_list_add (jd->d_inc_trs, transaction, 0); + osip_transaction_set_your_instance (transaction, + __eXosip_new_jinfo (jc, jd, NULL, NULL)); + __eXosip_wakeup (); + return; +} + + +static void +eXosip_process_newrequest (osip_event_t * evt, int socket) +{ + osip_transaction_t *transaction; + osip_event_t *evt_answer; + osip_message_t *answer; + int i; + int ctx_type; + eXosip_call_t *jc; + eXosip_subscribe_t *js; + eXosip_notify_t *jn; + eXosip_dialog_t *jd; + + if (MSG_IS_INVITE (evt->sip)) + { + ctx_type = IST; + } else if (MSG_IS_ACK (evt->sip)) + { /* this should be a ACK for 2xx (but could be a late ACK!) */ + ctx_type = -1; + } else if (MSG_IS_REQUEST (evt->sip)) + { + ctx_type = NIST; + } else + { /* We should handle late response and 200 OK before coming here. */ + ctx_type = -1; + osip_event_free (evt); + return; + } + + transaction = NULL; + if (ctx_type != -1) + { + i = osip_transaction_init (&transaction, + (osip_fsm_type_t) ctx_type, + eXosip.j_osip, evt->sip); + if (i != 0) + { + osip_event_free (evt); + return; + } + + osip_transaction_set_in_socket(transaction, socket); + osip_transaction_set_out_socket(transaction, socket); + + evt->transactionid = transaction->transactionid; + osip_transaction_set_your_instance (transaction, NULL); + + osip_transaction_add_event (transaction, evt); + if (ctx_type == IST) + { + i = _eXosip_build_response_default (&answer, NULL, 100, evt->sip); + if (i != 0) + { + __eXosip_delete_jinfo (transaction); + osip_transaction_free (transaction); + return; + } + + osip_message_set_content_length (answer, "0"); + /* send message to transaction layer */ + + evt_answer = osip_new_outgoing_sipmessage (answer); + evt_answer->transactionid = transaction->transactionid; + + /* add the REQUEST & the 100 Trying */ + osip_transaction_add_event (transaction, evt_answer); + __eXosip_wakeup (); + } + } + + if (MSG_IS_CANCEL (evt->sip)) + { + /* special handling for CANCEL */ + /* in the new spec, if the CANCEL has a Via branch, then it + is the same as the one in the original INVITE */ + eXosip_process_cancel (transaction, evt); + return; + } + + jd = NULL; + /* first, look for a Dialog in the map of element */ + for (jc = eXosip.j_calls; jc != NULL; jc = jc->next) + { + for (jd = jc->c_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog != NULL) + { + if (osip_dialog_match_as_uas (jd->d_dialog, evt->sip) == 0) + break; + } + } + if (jd != NULL) + break; + } + + + if (jd != NULL) + { + osip_transaction_t *old_trn; + + /* it can be: + 1: a new INVITE offer. + 2: a REFER request from one of the party. + 2: a BYE request from one of the party. + 3: a REQUEST with a wrong CSeq. + 4: a NOT-SUPPORTED method with a wrong CSeq. + */ + + if (!MSG_IS_BYE (evt->sip)) + { + /* reject all requests for a closed dialog */ + old_trn = eXosip_find_last_inc_transaction (jc, jd, "BYE"); + if (old_trn == NULL) + old_trn = eXosip_find_last_out_transaction (jc, jd, "BYE"); + + if (old_trn != NULL) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 481, NULL, + NULL, __LINE__); + return; + } + } + + if (MSG_IS_INVITE (evt->sip)) + { + /* the previous transaction MUST be freed */ + old_trn = eXosip_find_last_inc_invite (jc, jd); + + if (old_trn != NULL && old_trn->state != IST_TERMINATED) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 500, + "Retry Later", + "An INVITE is not terminated", __LINE__); + return; + } + + old_trn = eXosip_find_last_out_invite (jc, jd); + if (old_trn != NULL && old_trn->state != ICT_TERMINATED) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 491, NULL, + NULL, __LINE__); + return; + } + + osip_dialog_update_osip_cseq_as_uas (jd->d_dialog, evt->sip); + osip_dialog_update_route_set_as_uas (jd->d_dialog, evt->sip); + + eXosip_process_reinvite (jc, jd, transaction, evt); + } else if (MSG_IS_BYE (evt->sip)) + { + old_trn = eXosip_find_last_inc_transaction (jc, jd, "BYE"); + + if (old_trn != NULL) /* && old_trn->state!=NIST_TERMINATED) */ + { /* this situation should NEVER occur?? (we can't receive + two different BYE for one call! */ + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 500, + "Call Already Terminated", + "A pending BYE has already terminate this call", + __LINE__); + return; + } + /* osip_transaction_free(old_trn); */ + eXosip_process_bye (jc, jd, transaction, evt); + } else if (MSG_IS_ACK (evt->sip)) + { + eXosip_process_ack (jc, jd, evt); + } else if (MSG_IS_REFER (evt->sip)) + { + eXosip_process_refer (jc, jd, transaction, evt); + } else if (MSG_IS_OPTIONS (evt->sip)) + { + eXosip_process_options (jc, jd, transaction, evt); + } else if (MSG_IS_INFO (evt->sip)) + { + eXosip_process_info (jc, jd, transaction, evt); + } else if (MSG_IS_NOTIFY (evt->sip)) + { + eXosip_process_notify_for_refer (jc, jd, transaction, evt); + } else if (MSG_IS_PRACK (evt->sip)) + { + eXosip_process_prack (jc, jd, transaction, evt); + } else if (MSG_IS_MESSAGE (evt->sip)) + { + eXosip_process_message_within_dialog (jc, jd, transaction, evt); + } else if (MSG_IS_SUBSCRIBE (evt->sip)) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 489, NULL, + "Bad Event", __LINE__); + } else + { +#if 0 + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 405, NULL, + "Method Not Allowed", __LINE__); +#else + eXosip_process_message_within_dialog (jc, jd, transaction, evt); +#endif + } + return; + } + + if (MSG_IS_ACK (evt->sip)) + { + /* no transaction has been found for this ACK! */ + osip_event_free (evt); + return; + } + + if (MSG_IS_INFO (evt->sip)) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 481, NULL, NULL, __LINE__); + return; /* fixed */ + } + if (MSG_IS_OPTIONS (evt->sip)) + { + eXosip_process_new_options (transaction, evt); + return; + } else if (MSG_IS_INVITE (evt->sip)) + { + eXosip_process_new_invite (transaction, evt); + return; + } else if (MSG_IS_BYE (evt->sip)) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 481, NULL, NULL, __LINE__); + return; + } + + js = NULL; + /* first, look for a Dialog in the map of element */ + for (js = eXosip.j_subscribes; js != NULL; js = js->next) + { + for (jd = js->s_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog != NULL) + { + if (osip_dialog_match_as_uas (jd->d_dialog, evt->sip) == 0) + break; + } + } + if (jd != NULL) + break; + } + + if (js != NULL) + { + /* dialog found */ + osip_transaction_t *old_trn; + + /* it can be: + 1: a new INVITE offer. + 2: a REFER request from one of the party. + 2: a BYE request from one of the party. + 3: a REQUEST with a wrong CSeq. + 4: a NOT-SUPPORTED method with a wrong CSeq. + */ + if (MSG_IS_MESSAGE (evt->sip)) + { + /* eXosip_process_imessage_within_subscribe_dialog(transaction, evt); */ + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, + SIP_NOT_IMPLEMENTED, NULL, + "MESSAGEs within dialogs are not implemented.", + __LINE__); + return; + } else if (MSG_IS_NOTIFY (evt->sip)) + { + /* the previous transaction MUST be freed */ + old_trn = eXosip_find_last_inc_notify (js, jd); + + /* shouldn't we wait for the COMPLETED state? */ + if (old_trn != NULL && old_trn->state != NIST_TERMINATED) + { + /* retry later? */ + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 500, + "Retry Later", + "A pending NOTIFY is not terminated", + __LINE__); + return; + } + + osip_dialog_update_osip_cseq_as_uas (jd->d_dialog, evt->sip); + osip_dialog_update_route_set_as_uas (jd->d_dialog, evt->sip); + + eXosip_process_notify_within_dialog (js, jd, transaction, evt); + } else + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 501, NULL, + "Just Not Implemented", __LINE__); + } + return; + } + + if (MSG_IS_NOTIFY (evt->sip)) + { + /* let's try to check if the NOTIFY is related to an existing + subscribe */ + js = NULL; + /* first, look for a Dialog in the map of element */ + for (js = eXosip.j_subscribes; js != NULL; js = js->next) + { + if (eXosip_match_notify_for_subscribe (js, evt->sip) == 0) + { + i = eXosip_dialog_init_as_uac (&jd, evt->sip); + if (i != 0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "eXosip: cannot establish a dialog\n")); + return; + } + + /* update local cseq from subscribe request */ + if (js->s_out_tr != NULL && js->s_out_tr->cseq != NULL + && js->s_out_tr->cseq->number != NULL) + { + jd->d_dialog->local_cseq = atoi (js->s_out_tr->cseq->number); + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: local cseq has been updated\n")); + } + + ADD_ELEMENT (js->s_dialogs, jd); + eXosip_update (); + + eXosip_process_notify_within_dialog (js, jd, transaction, evt); + return; + } + } + + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (NULL, transaction, evt, 481, NULL, NULL, + __LINE__); + return; + } + + jn = NULL; + /* first, look for a Dialog in the map of element */ + for (jn = eXosip.j_notifies; jn != NULL; jn = jn->next) + { + for (jd = jn->n_dialogs; jd != NULL; jd = jd->next) + { + if (jd->d_dialog != NULL) + { + if (osip_dialog_match_as_uas (jd->d_dialog, evt->sip) == 0) + break; + } + } + if (jd != NULL) + break; + } + + if (jn != NULL) + { + /* dialog found */ + osip_transaction_t *old_trn; + + /* it can be: + 1: a new INVITE offer. + 2: a REFER request from one of the party. + 2: a BYE request from one of the party. + 3: a REQUEST with a wrong CSeq. + 4: a NOT-SUPPORTED method with a wrong CSeq. + */ + if (MSG_IS_MESSAGE (evt->sip)) + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, + SIP_NOT_IMPLEMENTED, NULL, + "MESSAGEs within dialogs are not implemented.", + __LINE__); + return; + } else if (MSG_IS_SUBSCRIBE (evt->sip)) + { + /* the previous transaction MUST be freed */ + old_trn = eXosip_find_last_inc_subscribe (jn, jd); + + /* shouldn't we wait for the COMPLETED state? */ + if (old_trn != NULL && old_trn->state != NIST_TERMINATED + && old_trn->state != NIST_COMPLETED) + { + /* retry later? */ + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 500, + "Retry Later", + "A SUBSCRIBE is not terminated", + __LINE__); + return; + } + + osip_dialog_update_osip_cseq_as_uas (jd->d_dialog, evt->sip); + osip_dialog_update_route_set_as_uas (jd->d_dialog, evt->sip); + + eXosip_process_subscribe_within_call (jn, jd, transaction, evt); + } else + { + osip_list_add (eXosip.j_transactions, transaction, 0); + eXosip_send_default_answer (jd, transaction, evt, 501, NULL, NULL, + __LINE__); + } + return; + } + + if (MSG_IS_MESSAGE (evt->sip)) + { + eXosip_process_message_outside_of_dialog (transaction, evt); + return; + } + + if (MSG_IS_REFER (evt->sip)) + { + eXosip_process_refer_outside_of_dialog (transaction, evt); + return; + } + + if (MSG_IS_SUBSCRIBE (evt->sip)) + { + + if (0 == eXosip_event_package_is_supported (transaction, evt)) + { + return; + } + eXosip_process_new_subscribe (transaction, evt); + return; + } + + /* default answer */ + osip_list_add (eXosip.j_transactions, transaction, 0); +#if 0 + eXosip_send_default_answer (NULL, transaction, evt, 501, NULL, NULL, __LINE__); +#endif +} + +static void +eXosip_process_response_out_of_transaction (osip_event_t * evt) +{ + osip_event_free (evt); +} + +static int _eXosip_handle_incoming_message(char *buf, size_t len, int socket, + char *host, int port); + +static int _eXosip_handle_incoming_message(char *buf, size_t len, int socket, + char *host, int port) +{ + osip_transaction_t *transaction = NULL; + osip_event_t *sipevent; + int i; + + sipevent = osip_parse (buf, len); + transaction = NULL; + if (sipevent != NULL && sipevent->sip != NULL) + { + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Could not parse SIP message\n")); + osip_event_free (sipevent); + return -1; + } + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message received from: %s:%i\n", + host, port)); + + osip_message_fix_last_via_header (sipevent->sip, + host, + port); + + i = osip_find_transaction_and_add_event (eXosip.j_osip, sipevent); + if (i != 0) + { + /* this event has no transaction, */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "This is a request\n", buf)); + eXosip_lock (); + if (MSG_IS_REQUEST (sipevent->sip)) + eXosip_process_newrequest (sipevent, socket); + else if (MSG_IS_RESPONSE (sipevent->sip)) + eXosip_process_response_out_of_transaction (sipevent); + eXosip_unlock (); + } + else + { + /* handled by oSIP ! */ + return 0; + } + return 0; +} + +#if defined (WIN32) || defined (_WIN32_WCE) +#define eXFD_SET(A, B) FD_SET((unsigned int) A, B) +#else +#define eXFD_SET(A, B) FD_SET(A, B) +#endif + +/* if second==-1 && useconds==-1 -> wait for ever + if max_message_nb<=0 -> infinite loop.... */ +int +eXosip_read_message (int max_message_nb, int sec_max, int usec_max) +{ + fd_set osip_fdset; + struct timeval tv; + char *buf; + + tv.tv_sec = sec_max; + tv.tv_usec = usec_max; + + buf = (char *) osip_malloc (SIP_MESSAGE_MAX_LENGTH * sizeof (char) + 1); + while (max_message_nb != 0 && eXosip.j_stop_ua == 0) + { + int i; + int max; + int wakeup_socket = jpipe_get_read_descr (eXosip.j_socketctl); + + FD_ZERO (&osip_fdset); + if (eXosip.net_interfaces[0].net_socket>0) + { + eXFD_SET (eXosip.net_interfaces[0].net_socket, &osip_fdset); + max = eXosip.net_interfaces[0].net_socket; + } + if (eXosip.net_interfaces[1].net_socket>0) + { + int pos; + struct eXosip_net *net = &eXosip.net_interfaces[1]; + eXFD_SET (net->net_socket, &osip_fdset); + if (net->net_socket>max) + max = net->net_socket; + + for (pos=0;pos<EXOSIP_MAX_SOCKETS;pos++) + { + if (net->net_socket_tab[pos].socket!=0) + { + eXFD_SET (net->net_socket_tab[pos].socket, &osip_fdset); + if (net->net_socket_tab[pos].socket>max) + max = net->net_socket_tab[pos].socket; + } + } + } + + if (eXosip.net_interfaces[2].net_socket>0) + { + eXFD_SET (eXosip.net_interfaces[2].net_socket, &osip_fdset); + if (eXosip.net_interfaces[2].net_socket>max) + max = eXosip.net_interfaces[2].net_socket; + } + + + eXFD_SET (wakeup_socket, &osip_fdset); + if (wakeup_socket > max) + max = wakeup_socket; + + if ((sec_max == -1) || (usec_max == -1)) + i = select (max + 1, &osip_fdset, NULL, NULL, NULL); + else + i = select (max + 1, &osip_fdset, NULL, NULL, &tv); + + if ((i == -1) && (errno == EINTR || errno == EAGAIN)) + continue; + + if ((i > 0) && FD_ISSET (wakeup_socket, &osip_fdset)) + { + char buf2[500]; + + jpipe_read (eXosip.j_socketctl, buf2, 499); + } + + if (0 == i || eXosip.j_stop_ua != 0) + { + } else if (-1 == i) + { + osip_free (buf); + return -2; /* error */ + } else if (FD_ISSET (eXosip.net_interfaces[1].net_socket, &osip_fdset)) + { + /* accept incoming connection */ + char src6host[NI_MAXHOST]; + int recvport = 0; + struct sockaddr_storage sa; + int sock; + int i; + int pos; +#ifdef __linux + socklen_t slen; +#else + int slen; +#endif + if (ipv6_enable == 0) + slen = sizeof (struct sockaddr_in); + else + slen = sizeof (struct sockaddr_in6); + + for (pos=0; pos<EXOSIP_MAX_SOCKETS; pos++) + { + if (eXosip.net_interfaces[1].net_socket_tab[pos].socket==0) + break; + } + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "creating TCP socket at index: %i\n", pos)); + sock = accept(eXosip.net_interfaces[1].net_socket, (struct sockaddr *) &sa, + &slen); + if (sock<0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Error accepting TCP socket\n")); + break; + } + eXosip.net_interfaces[1].net_socket_tab[pos].socket = sock; + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "New TCP connection accepted\n")); + + memset(src6host, 0, sizeof(src6host)); + + if (ipv6_enable == 0) + recvport = ntohs (((struct sockaddr_in*)&sa)->sin_port); + else + recvport = ntohs (((struct sockaddr_in6*)&sa)->sin6_port); + + i = getnameinfo((struct sockaddr*)&sa, slen, + src6host, NI_MAXHOST, + NULL, 0, + NI_NUMERICHOST); + + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Message received from: %s:%i Error with getnameinfo\n", + src6host, recvport)); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message received from: %s:%i\n", + src6host, recvport)); + osip_strncpy(eXosip.net_interfaces[1].net_socket_tab[pos].remote_ip, + src6host, + sizeof(eXosip.net_interfaces[1].net_socket_tab[pos].remote_ip)); + eXosip.net_interfaces[1].net_socket_tab[pos].remote_port = recvport; + } + + } else if (FD_ISSET (eXosip.net_interfaces[0].net_socket, &osip_fdset)) + { + /*AMDstruct sockaddr_in sa; */ + struct sockaddr_storage sa; + +#ifdef __linux + socklen_t slen; +#else + int slen; +#endif + if (ipv6_enable == 0) + slen = sizeof (struct sockaddr_in); + else + slen = sizeof (struct sockaddr_in6); + + i = _eXosip_recvfrom (eXosip.net_interfaces[0].net_socket, buf, SIP_MESSAGE_MAX_LENGTH, 0, + (struct sockaddr *) &sa, &slen); + + if (i > 5) /* we expect at least one byte, otherwise there's no doubt that it is not a sip message ! */ + { + /* Message might not end with a "\0" but we know the number of */ + /* char received! */ + osip_transaction_t *transaction = NULL; + osip_event_t *sipevent; + + osip_strncpy (buf + i, "\0", 1); + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Received message: \n%s\n", buf)); +#ifdef WIN32 + if (strlen (buf) > 412) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message suite: \n%s\n", buf + 412)); + } +#endif + + sipevent = osip_parse (buf, i); + transaction = NULL; + if (sipevent != NULL && sipevent->sip != NULL) + { + if (!eXosip.http_port) + { + char src6host[NI_MAXHOST]; + char src6buf[NI_MAXSERV]; + int recvport = 0; + memset(src6host, 0, sizeof(src6host)); + memset(src6buf, 0, sizeof(src6buf)); + + if (ipv6_enable == 0) + recvport = ntohs (((struct sockaddr_in*)&sa)->sin_port); + else + recvport = ntohs (((struct sockaddr_in6*)&sa)->sin6_port); + + i = getnameinfo((struct sockaddr*)&sa, slen, + src6host, NI_MAXHOST, + NULL, 0, + NI_NUMERICHOST); + + if (i!=0) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Message received from: %s:%i (serv=%s) Error with getnameinfo\n", + src6host, recvport, src6buf)); + } + else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message received from: %s:%i (serv=%s)\n", + src6host, recvport, src6buf)); + } + + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message received from: %s:%i (serv=%s)\n", + src6host, recvport, src6buf)); + + osip_message_fix_last_via_header (sipevent->sip, + src6host, + recvport); + } + i = + osip_find_transaction_and_add_event (eXosip.j_osip, sipevent); + if (i != 0) + { + /* this event has no transaction, */ + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "This is a request\n", buf)); + eXosip_lock (); + if (MSG_IS_REQUEST (sipevent->sip)) + eXosip_process_newrequest (sipevent, 0); + else if (MSG_IS_RESPONSE (sipevent->sip)) + eXosip_process_response_out_of_transaction (sipevent); + eXosip_unlock (); + } else + { + /* handled by oSIP ! */ + } + } else + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Could not parse SIP message\n")); + osip_event_free (sipevent); + } + } else if (i < 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Could not read socket\n")); + } else + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Dummy SIP message received\n")); + } + } + else + { + /* loop over all TCP socket */ + int pos = 0; + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "TCP DATA ready?\n")); + for (pos=0; pos<EXOSIP_MAX_SOCKETS; pos++) + { + if (eXosip.net_interfaces[1].net_socket_tab[pos].socket>0 + && FD_ISSET (eXosip.net_interfaces[1].net_socket_tab[pos].socket, &osip_fdset)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "TCP DATA ready! message received\n")); + i = recv (eXosip.net_interfaces[1].net_socket_tab[pos].socket, + buf, SIP_MESSAGE_MAX_LENGTH, 0); + if (i > 5) + { + osip_strncpy (buf + i, "\0", 1); + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Received TCP message: \n%s\n", buf)); +#ifdef WIN32 + if (strlen (buf) > 412) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Message suite: \n%s\n", buf + 412)); + } +#endif + _eXosip_handle_incoming_message(buf, i, + eXosip.net_interfaces[1].net_socket_tab[pos].socket, + eXosip.net_interfaces[1].net_socket_tab[pos].remote_ip, + eXosip.net_interfaces[1].net_socket_tab[pos].remote_port); + } + else if (i < 0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, + "Could not read socket - close it\n")); + close(eXosip.net_interfaces[1].net_socket_tab[pos].socket); + memset(&(eXosip.net_interfaces[1].net_socket_tab[pos]), + 0, sizeof(struct eXosip_socket)); + } + else if (i==0) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "End of stream (read 0 byte from %s:%i)\n", eXosip.net_interfaces[1].net_socket_tab[pos].remote_ip, eXosip.net_interfaces[1].net_socket_tab[pos].remote_port)); + close(eXosip.net_interfaces[1].net_socket_tab[pos].socket); + memset(&(eXosip.net_interfaces[1].net_socket_tab[pos]), + 0, sizeof(struct eXosip_socket)); + } + else + { + /* we expect at least one byte, otherwise there's no doubt that it is not a sip message ! */ + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Dummy SIP message received (size=%i)\n", i)); + } + } + } + } + + + max_message_nb--; + } + osip_free (buf); + return 0; +} + + +static int +eXosip_pendingosip_transaction_exist (eXosip_call_t * jc, eXosip_dialog_t * jd) +{ + osip_transaction_t *tr; + int now = time (NULL); + + tr = eXosip_find_last_inc_transaction (jc, jd, "BYE"); + if (tr != NULL && tr->state != NIST_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time + 180 < now) /* Wait a max of 2 minutes */ + { + /* remove the transaction from oSIP: */ + osip_remove_transaction (eXosip.j_osip, tr); + eXosip_remove_transaction_from_call (tr, jc); + osip_list_add (eXosip.j_transactions, tr, 0); + } else + return 0; + } + + tr = eXosip_find_last_out_transaction (jc, jd, "BYE"); + if (tr != NULL && tr->state != NICT_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time + 180 < now) /* Wait a max of 2 minutes */ + { + /* remove the transaction from oSIP: */ + osip_remove_transaction (eXosip.j_osip, tr); + eXosip_remove_transaction_from_call (tr, jc); + osip_list_add (eXosip.j_transactions, tr, 0); + } else + return 0; + } + + tr = eXosip_find_last_inc_invite (jc, jd); + if (tr != NULL && tr->state != IST_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time + 180 < now) /* Wait a max of 2 minutes */ + { + /* remove the transaction from oSIP: */ + /* osip_remove_transaction(eXosip.j_osip, tr); + eXosip_remove_transaction_from_call(tr, jc); + osip_transaction_free(tr); */ + } else + return 0; + } + + tr = eXosip_find_last_out_invite (jc, jd); + if (tr != NULL && tr->state != ICT_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time + 180 < now) /* Wait a max of 2 minutes */ + { + /* remove the transaction from oSIP: */ + /* osip_remove_transaction(eXosip.j_osip, tr); + eXosip_remove_transaction_from_call(tr, jc); + osip_transaction_free(tr); */ + } else + return 0; + } + + tr = eXosip_find_last_inc_transaction (jc, jd, "REFER"); + if (tr != NULL && tr->state != IST_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time + 180 < now) /* Wait a max of 2 minutes */ + { + /* remove the transaction from oSIP: */ + osip_remove_transaction (eXosip.j_osip, tr); + eXosip_remove_transaction_from_call (tr, jc); + osip_list_add (eXosip.j_transactions, tr, 0); + } else + return 0; + } + + tr = eXosip_find_last_out_transaction (jc, jd, "REFER"); + if (tr != NULL && tr->state != NICT_TERMINATED) + { /* Don't want to wait forever on broken transaction!! */ + if (tr->birth_time + 180 < now) /* Wait a max of 2 minutes */ + { + /* remove the transaction from oSIP: */ + osip_remove_transaction (eXosip.j_osip, tr); + eXosip_remove_transaction_from_call (tr, jc); + osip_list_add (eXosip.j_transactions, tr, 0); + } else + return 0; + } + + return -1; +} + +static int +eXosip_release_finished_calls (eXosip_call_t * jc, eXosip_dialog_t * jd) +{ + osip_transaction_t *tr; + + tr = eXosip_find_last_inc_transaction (jc, jd, "BYE"); + if (tr == NULL) + tr = eXosip_find_last_out_transaction (jc, jd, "BYE"); + + if (tr != NULL && (tr->state == NIST_TERMINATED || tr->state == NICT_TERMINATED)) + { + int did = -2; + if (jd!=NULL) + did = jd->d_id; + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_finished_calls remove a dialog (cid=%i did=%i)\n", jc->c_id, did)); + /* Remove existing reference to the dialog from transactions! */ + __eXosip_call_remove_dialog_reference_in_call (jc, jd); + REMOVE_ELEMENT (jc->c_dialogs, jd); + eXosip_dialog_free (jd); + return 0; + } + return -1; +} + + + +static void +__eXosip_release_call (eXosip_call_t * jc, eXosip_dialog_t * jd) +{ + REMOVE_ELEMENT (eXosip.j_calls, jc); + report_call_event (EXOSIP_CALL_RELEASED, jc, jd, NULL); + eXosip_call_free (jc); + __eXosip_wakeup (); +} + + +static int +eXosip_release_aborted_calls (eXosip_call_t * jc, eXosip_dialog_t * jd) +{ + int now = time (NULL); + osip_transaction_t *tr; + +#if 0 + tr = eXosip_find_last_inc_invite (jc, jd); + if (tr == NULL) + tr = eXosip_find_last_out_invite (jc, jd); +#else + /* close calls only when the initial INVITE failed */ + tr = jc->c_inc_tr; + if (tr==NULL) + tr = jc->c_out_tr; +#endif + + if (tr == NULL) + { + if (jd != NULL) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls remove an empty dialog\n")); + __eXosip_call_remove_dialog_reference_in_call (jc, jd); + REMOVE_ELEMENT (jc->c_dialogs, jd); + eXosip_dialog_free (jd); + return 0; + } + return -1; + } + + if (tr != NULL && tr->state != IST_TERMINATED && tr->state != ICT_TERMINATED && tr->birth_time + 180 < now) /* Wait a max of 2 minutes */ + { + if (jd != NULL) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls remove a dialog for an unfinished transaction\n")); + __eXosip_call_remove_dialog_reference_in_call (jc, jd); + REMOVE_ELEMENT (jc->c_dialogs, jd); + report_call_event (EXOSIP_CALL_NOANSWER, jc, jd, NULL); + eXosip_dialog_free (jd); + __eXosip_wakeup (); + return 0; + } + } + + if (tr != NULL && (tr->state == IST_TERMINATED || tr->state == ICT_TERMINATED)) + { + if (tr == jc->c_inc_tr) + { + if (jc->c_inc_tr->last_response == NULL) + { + /* OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_INFO2,NULL, + "eXosip: eXosip_release_aborted_calls transaction with no answer\n")); */ + } else if (MSG_IS_STATUS_3XX (jc->c_inc_tr->last_response)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls answered with a 3xx\n")); + __eXosip_release_call (jc, jd); + return 0; + } else if (MSG_IS_STATUS_4XX (jc->c_inc_tr->last_response)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls answered with a 4xx\n")); + __eXosip_release_call (jc, jd); + return 0; + } else if (MSG_IS_STATUS_5XX (jc->c_inc_tr->last_response)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls answered with a 5xx\n")); + __eXosip_release_call (jc, jd); + return 0; + } else if (MSG_IS_STATUS_6XX (jc->c_inc_tr->last_response)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls answered with a 6xx\n")); + __eXosip_release_call (jc, jd); + return 0; + } + } else if (tr == jc->c_out_tr) + { + if (jc->c_out_tr->last_response == NULL) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls completed with no answer\n")); + __eXosip_release_call (jc, jd); + return 0; + } else if (MSG_IS_STATUS_3XX (jc->c_out_tr->last_response)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls completed answered with 3xx\n")); + __eXosip_release_call (jc, jd); + return 0; + } else if (MSG_IS_STATUS_4XX (jc->c_out_tr->last_response)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls completed answered with 4xx\n")); + __eXosip_release_call (jc, jd); + return 0; + } else if (MSG_IS_STATUS_5XX (jc->c_out_tr->last_response)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls completed answered with 5xx\n")); + __eXosip_release_call (jc, jd); + return 0; + } else if (MSG_IS_STATUS_6XX (jc->c_out_tr->last_response)) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_aborted_calls completed answered with 6xx\n")); + __eXosip_release_call (jc, jd); + return 0; + } + } + } + + return -1; +} + + +void +eXosip_release_terminated_calls (void) +{ + eXosip_dialog_t *jd; + eXosip_dialog_t *jdnext; + eXosip_call_t *jc; + eXosip_call_t *jcnext; + int now = time (NULL); + int pos; + + + for (jc = eXosip.j_calls; jc != NULL;) + { + jcnext = jc->next; + /* free call terminated with a BYE */ + + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: working on (cid=%i)\n", jc->c_id)); + for (jd = jc->c_dialogs; jd != NULL;) + { + jdnext = jd->next; + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: working on (cid=%i did=%i)\n", jc->c_id, jd->d_id)); + if (0 == eXosip_pendingosip_transaction_exist (jc, jd)) + { + } else if (0 == eXosip_release_finished_calls (jc, jd)) + { + jd = jc->c_dialogs; + } else if (0 == eXosip_release_aborted_calls (jc, jd)) + { + jdnext = NULL; + } else if (jd->d_id==-1) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, + "eXosip: eXosip_release_terminated_calls delete a removed dialog (cid=%i did=%i)\n", jc->c_id, jd->d_id)); + /* Remove existing reference to the dialog from transactions! */ + __eXosip_call_remove_dialog_reference_in_call (jc, jd); + REMOVE_ELEMENT (jc->c_dialogs, jd); + eXosip_dialog_free (jd); + + jd = jc->c_dialogs; + } + jd = jdnext; + } + jc = jcnext; + } + + for (jc = eXosip.j_calls; jc != NULL;) + { + jcnext = jc->next; + if (jc->c_dialogs == NULL) + { + /* release call for options requests */ + if (jc->c_inc_options_tr != NULL) + { + if (jc->c_inc_options_tr->state == NIST_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: remove an incoming OPTIONS with no final answer\n")); + __eXosip_release_call (jc, NULL); + } else if (jc->c_inc_options_tr->state != NIST_TERMINATED + && jc->c_inc_options_tr->birth_time + 180 < now) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: remove an incoming OPTIONS with no final answer\n")); + __eXosip_release_call (jc, NULL); + } + } else if (jc->c_out_options_tr != NULL) + { + if (jc->c_out_options_tr->state == NICT_TERMINATED) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: remove an outgoing OPTIONS with no final answer\n")); + __eXosip_release_call (jc, NULL); + } else if (jc->c_out_options_tr->state != NIST_TERMINATED + && jc->c_out_options_tr->birth_time + 180 < now) + { + OSIP_TRACE (osip_trace + (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: remove an outgoing OPTIONS with no final answer\n")); + __eXosip_release_call (jc, NULL); + } + } else if (jc->c_inc_tr != NULL + && jc->c_inc_tr->state != IST_TERMINATED + && jc->c_inc_tr->birth_time + 180 < now) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: remove an incoming call with no final answer\n")); + __eXosip_release_call (jc, NULL); + } else if (jc->c_out_tr != NULL + && jc->c_out_tr->state != ICT_TERMINATED + && jc->c_out_tr->birth_time + 180 < now) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: remove an outgoing call with no final answer\n")); + __eXosip_release_call (jc, NULL); + } else if (jc->c_inc_tr != NULL && jc->c_inc_tr->state != IST_TERMINATED) + { + } else if (jc->c_out_tr != NULL && jc->c_out_tr->state != ICT_TERMINATED) + { + } else /* no active pending transaction */ + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "eXosip: remove a call\n")); + __eXosip_release_call (jc, NULL); + } + } + jc = jcnext; + } + + pos = 0; + while (!osip_list_eol (eXosip.j_transactions, pos)) + { + osip_transaction_t *tr = + (osip_transaction_t *) osip_list_get (eXosip.j_transactions, pos); + if (tr->state == IST_TERMINATED || tr->state == ICT_TERMINATED + || tr->state == NICT_TERMINATED || tr->state == NIST_TERMINATED) + + { /* free (transaction is already removed from the oSIP stack) */ + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Release a terminated transaction\n")); + osip_list_remove (eXosip.j_transactions, pos); + __eXosip_delete_jinfo (tr); + osip_transaction_free (tr); + } else if (tr->birth_time + 180 < now) /* Wait a max of 2 minutes */ + { + osip_list_remove (eXosip.j_transactions, pos); + __eXosip_delete_jinfo (tr); + osip_transaction_free (tr); + } else + pos++; + } +} + +void +eXosip_release_terminated_registrations (void) +{ + eXosip_reg_t *jr; + eXosip_reg_t *jrnext; + int now = time (NULL); + + for (jr = eXosip.j_reg; jr != NULL;) + { + jrnext = jr->next; + if (jr->r_reg_period == 0 && jr->r_last_tr!=NULL) + { + if (now - jr->r_last_tr->birth_time > 60) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Release a terminated registration\n")); + REMOVE_ELEMENT (eXosip.j_reg, jr); + eXosip_reg_free (jr); + } + else if (jr->r_last_tr->last_response!=NULL + && jr->r_last_tr->last_response->status_code>=200 + && jr->r_last_tr->last_response->status_code<=299) + { + OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, + "Release a terminated registration with 2xx\n")); + REMOVE_ELEMENT (eXosip.j_reg, jr); + eXosip_reg_free (jr); + } + } + + jr = jrnext; + } + + return; +} diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..72f64586eb06c1dcd9ca6107ea0872d509d76ef4 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,3 @@ + +SUBDIRS = eXosip2 + diff --git a/include/eXosip2/Makefile.am b/include/eXosip2/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..5344a8b4c47d96f6e9df2dcc2533bd64b940e157 --- /dev/null +++ b/include/eXosip2/Makefile.am @@ -0,0 +1,6 @@ + + +noinst_HEADERS= eXosip.h eX_setup.h \ +eX_register.h eX_call.h eX_options.h eX_refer.h \ +eX_subscribe.h eX_publish.h eX_message.h + diff --git a/include/eXosip2/eX_call.h b/include/eXosip2/eX_call.h new file mode 100644 index 0000000000000000000000000000000000000000..b42d47b85220aaff8e85918b8c45276bcfe8b781 --- /dev/null +++ b/include/eXosip2/eX_call.h @@ -0,0 +1,231 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EX_CALL_H__ +#define __EX_CALL_H__ + +#include <osipparser2/osip_parser.h> +#include <osipparser2/sdp_message.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file eX_call.h + * @brief eXosip call API + * + * This file provide the API needed to control calls. You can + * use it to: + * + * <ul> + * <li>build initial invite.</li> + * <li>send initial invite.</li> + * <li>build request within the call.</li> + * <li>send request within the call.</li> + * </ul> + * + * This API can be used to build the following messages: + * <pre> + * INVITE, INFO, OPTIONS, REFER, UPDATE, NOTIFY + * </pre> + */ + +/** + * @defgroup eXosip2_call eXosip2 INVITE and Call Management + * @ingroup eXosip2_msg + * @{ + */ + + struct eXosip_call_t; + +/** + * Set a new application context for an existing call + * + * @param id call-id or dialog-id of call + * @param reference New application context. + */ + int eXosip_call_set_reference(int id, void *reference); + +/** + * Build a default INVITE message for a new call. + * + * @param invite Pointer for the SIP element to hold. + * @param to SIP url for callee. + * @param from SIP url for caller. + * @param route Route header for INVITE. (optionnal) + * @param subject Subject for the call. + */ + int eXosip_call_build_initial_invite(osip_message_t **invite, const char *to, + const char *from, const char *route, + const char *subject); + +/** + * Initiate a call. + * + * @param invite SIP INVITE message to send. + */ + int eXosip_call_send_initial_invite(osip_message_t *invite); + +/** + * Build a default request within a call. (INVITE, OPTIONS, INFO, REFER) + * + * @param did dialog id of call. + * @param method request type to build. + * @param request The sip request to build. + */ + int eXosip_call_build_request(int did, const char *method, + osip_message_t **request); + +/** + * Build a default ACK for a 200ok received. + * + * @param did dialog id of call. + * @param ack The sip request to build. + */ + int eXosip_call_build_ack(int did, osip_message_t **ack); + +/** + * Send the ACK for the 200ok received.. + * + * @param did dialog id of call. + * @param ack SIP ACK message to send. + */ + int eXosip_call_send_ack(int did, osip_message_t *ack); + +/** + * Build a default REFER for a call transfer. + * + * @param did dialog id of call. + * @param refer_to url for call transfer (Refer-To header). + * @param request The sip request to build. + */ + int eXosip_call_build_refer(int did, const char *refer_to, osip_message_t **request); + +/** + * Build a default INFO within a call. + * + * @param did dialog id of call. + * @param request The sip request to build. + */ + int eXosip_call_build_info(int did, osip_message_t **request); + +/** + * Build a default OPTIONS within a call. + * + * @param did dialog id of call. + * @param request The sip request to build. + */ + int eXosip_call_build_options(int did, osip_message_t **request); + +/** + * Build a default UPDATE within a call. + * + * @param did dialog id of call. + * @param request The sip request to build. + */ + int eXosip_call_build_update(int did, osip_message_t **request); + +/** + * Build a default NOTIFY within a call. + * + * @param did dialog id of call. + * @param subscription_status Subscription status of the request. + * @param request The sip request to build. + */ + int eXosip_call_build_notify(int did, int subscription_status, osip_message_t **request); + +/** + * send the request within call. (INVITE, OPTIONS, INFO, REFER, UPDATE) + * + * @param did dialog id of call. + * @param request The sip request to send. + */ + int eXosip_call_send_request(int did, osip_message_t *request); + +/** + * Build default Answer for request. + * + * @param tid id of transaction to answer. + * @param status Status code to use. + * @param answer The sip answer to build. + */ + int eXosip_call_build_answer(int tid, int status, osip_message_t **answer); + +/** + * Send Answer for invite. + * + * @param tid id of transaction to answer. + * @param status response status if answer is NULL. (not allowed for 2XX) + * @param answer The sip answer to send. + */ + int eXosip_call_send_answer(int tid, int status, osip_message_t *answer); + +/** + * Terminate a call. + * send CANCEL, BYE or 603 Decline. + * + * @param cid call id of call. + * @param did dialog id of call. + */ + int eXosip_call_terminate(int cid, int did); + +/** + * Build a PRACK for invite. + * + * @param tid id of the invite transaction. + * @param prack The sip prack to build. + */ + int eXosip_call_build_prack(int tid, osip_message_t **prack); + +/** + * Send a PRACK for invite. + * + * @param tid id of the invite transaction. + * @param prack The sip prack to send. + */ + int eXosip_call_send_prack(int tid, osip_message_t *prack); + +/** + * Send a NOTIFY containing the information about a call transfer. + * + * THIS METHOD WILL BE REPLACED or REMOVED, please use the + * new API to build NOTIFY. + * + * @param did dialog id of call. + * @param subscription_status the subscription status. + * @param body the body to attach to NOTIFY. + */ + int eXosip_transfer_send_notify(int did, int subscription_status, char *body); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eXosip2/eX_message.h b/include/eXosip2/eX_message.h new file mode 100644 index 0000000000000000000000000000000000000000..13f4a61ea4fb0d21f261101b353c51a87c1064a4 --- /dev/null +++ b/include/eXosip2/eX_message.h @@ -0,0 +1,108 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EX_MESSAGE_H__ +#define __EX_MESSAGE_H__ + +#include <osipparser2/osip_parser.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file eX_message.h + * @brief eXosip message request API + * + * This file provide the API needed to control MESSAGE requests. You can + * use it to: + * + * <ul> + * <li>build MESSAGE requests.</li> + * <li>send MESSAGE requests.</li> + * <li>build MESSAGE answers.</li> + * <li>send MESSAGE answers.</li> + * </ul> + */ + +/** + * @defgroup eXosip2_message eXosip2 MESSAGE and messaging services outside of dialog + * @ingroup eXosip2_msg + * @{ + */ + +/** + * Build a default MESSAGE message. + * + * This method will be updated to send any message outside of dialog + * In this later case, you'll specify the method to use in the second + * argument. + * + * By now, use this method only for the "MESSAGE" request. + * + * @param message Pointer for the SIP request to build. + * @param method request method. ("MESSAGE") + * @param to SIP url for callee. + * @param from SIP url for caller. + * @param route Route header for INVITE. (optionnal) + */ + int eXosip_message_build_request(osip_message_t **message, const char *method, + const char *to, const char *from, + const char *route); + +/** + * Send an MESSAGE request. + * + * @param message SIP MESSAGE message to send. + */ + int eXosip_message_send_request(osip_message_t *message); + +/** + * Build answer for an MESSAGE request. + * + * @param tid id of MESSAGE transaction. + * @param status status for SIP answer to build. + * @param answer The SIP answer to build. + */ + int eXosip_message_build_answer(int tid, int status, osip_message_t **answer); + +/** + * Send answer for an MESSAGE request. + * + * @param tid id of MESSAGE transaction. + * @param status status for SIP answer to send. + * @param answer The SIP answer to send. (default will be sent if NULL) + */ + int eXosip_message_send_answer(int tid, int status, osip_message_t *answer); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eXosip2/eX_options.h b/include/eXosip2/eX_options.h new file mode 100644 index 0000000000000000000000000000000000000000..a8325e96337e30a648c63bed9ea49cc8cca67f9c --- /dev/null +++ b/include/eXosip2/eX_options.h @@ -0,0 +1,100 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EX_OPTIONS_H__ +#define __EX_OPTIONS_H__ + +#include <osipparser2/osip_parser.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file eX_options.h + * @brief eXosip options request API + * + * This file provide the API needed to control OPTIONS requests. You can + * use it to: + * + * <ul> + * <li>build OPTIONS requests.</li> + * <li>send OPTIONS requests.</li> + * <li>build OPTIONS answers.</li> + * <li>send OPTIONS answers.</li> + * </ul> + */ + +/** + * @defgroup eXosip2_options eXosip2 OPTIONS and UA capabilities Management + * @ingroup eXosip2_msg + * @{ + */ + +/** + * Build a default OPTIONS message. + * + * @param options Pointer for the SIP request to build. + * @param to SIP url for callee. + * @param from SIP url for caller. + * @param route Route header for INVITE. (optionnal) + */ + int eXosip_options_build_request(osip_message_t **options, const char *to, + const char *from, const char *route); + +/** + * Send an OPTIONS request. + * + * @param options SIP OPTIONS message to send. + */ + int eXosip_options_send_request(osip_message_t *options); + +/** + * Build answer for an OPTIONS request. + * + * @param tid id of OPTIONS transaction. + * @param status status for SIP answer to build. + * @param answer The SIP answer to build. + */ + int eXosip_options_build_answer(int tid, int status, osip_message_t **answer); + +/** + * Send answer for an OPTIONS request. + * + * @param tid id of OPTIONS transaction. + * @param status status for SIP answer to send. + * @param answer The SIP answer to send. (default will be sent if NULL) + */ + int eXosip_options_send_answer(int tid, int status, osip_message_t *answer); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eXosip2/eX_publish.h b/include/eXosip2/eX_publish.h new file mode 100644 index 0000000000000000000000000000000000000000..ebc9ccead1be909b4538738eb12c9d59e788249b --- /dev/null +++ b/include/eXosip2/eX_publish.h @@ -0,0 +1,92 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EX_PUBLISH_H__ +#define __EX_PUBLISH_H__ + +#include <osipparser2/osip_parser.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file eX_publish.h + * @brief eXosip publish request API + * + * This file provide the API needed to control PUBLISH requests. You can + * use it to: + * + * <ul> + * <li>build PUBLISH requests.</li> + * <li>send PUBLISH requests.</li> + * </ul> + */ + +/** + * @defgroup eXosip2_publish eXosip2 Publication Management + * @ingroup eXosip2_msg + * @{ + */ + +/** + * build publication for a user. (PUBLISH request) + * + * @param message returned published request. + * @param to SIP url for callee. + * @param from SIP url for caller. + * @param route Route used for publication. + * @param event SIP Event header. + * @param expires SIP Expires header. + * @param ctype Content-Type of body. + * @param body body for publication. + */ +int eXosip_build_publish(osip_message_t **message, + const char *to, + const char *from, + const char *route, + const char *event, + const char *expires, + const char *ctype, + const char *body); + +/** + * Send an Publication Message (PUBLISH request). + * + * @param message is a ready to be sent publish message . + * @param sip_if_match is the SIP-If-Match header. (NULL for initial publication) + */ +int eXosip_publish (osip_message_t *message, const char *sip_if_match); + + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eXosip2/eX_refer.h b/include/eXosip2/eX_refer.h new file mode 100644 index 0000000000000000000000000000000000000000..3c46cf41efc4dff7f755ba265addc01cf5a8be63 --- /dev/null +++ b/include/eXosip2/eX_refer.h @@ -0,0 +1,84 @@ + +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EX_REFER_H__ +#define __EX_REFER_H__ + +#include <osipparser2/osip_parser.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file eX_refer.h + * @brief eXosip transfer outside of calls API + * + * This file provide the API needed to request a blind transfer + * outside of any call. + * + * <ul> + * <li>build initial refer.</li> + * <li>send initial refer.</li> + * </ul> + * + */ + +/** + * @defgroup eXosip2_refer eXosip2 REFER and blind tranfer Management outside of calls + * @ingroup eXosip2_msg + * @{ + */ + +/** + * Build a default REFER message for a blind transfer outside of any calls. + * + * @param refer Pointer for the SIP element to hold. + * @param refer_to SIP url for transfer. + * @param from SIP url for caller. + * @param to SIP url for callee. + * @param route Route header for REFER. (optionnal) + */ +int eXosip_refer_build_request(osip_message_t **refer, const char *refer_to, + const char *from, const char *to, + const char *route); + +/** + * Initiate a blind tranfer outside of any call. + * + * @param refer SIP REFER message to send. + */ +int eXosip_refer_send_request(osip_message_t *refer); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eXosip2/eX_register.h b/include/eXosip2/eX_register.h new file mode 100644 index 0000000000000000000000000000000000000000..e0919219a13532553f7eab0fe9372c5b4759cba1 --- /dev/null +++ b/include/eXosip2/eX_register.h @@ -0,0 +1,96 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EX_REGISTER_H__ +#define __EX_REGISTER_H__ + +#include <osipparser2/osip_parser.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * @file eX_register.h + * @brief eXosip registration API + * + * This file provide the API needed to control registrations. You can + * use it to: + * + * <ul> + * <li>build initial REGISTER.</li> + * <li>build REGISTER.</li> + * <li>send REGISTER.</li> + * </ul> + */ + +/** + * @defgroup eXosip2_registration eXosip2 REGISTER and Registration Management + * @ingroup eXosip2_msg + * @{ + */ + + struct eXosip_reg_t; + +/** + * Build initial REGISTER request. + * + * @param from SIP url for caller. + * @param proxy Proxy used for registration. + * @param contact Contact address. (optional) + * @param expires The expires value for registration. + * @param reg The SIP request to build. + */ + int eXosip_register_build_initial_register(const char *from, const char *proxy, + const char *contact, int expires, + osip_message_t **reg); + +/** + * Build a new REGISTER request for an existing registration. + * + * @param rid A unique identifier for the registration context + * @param expires The expires value for registration. + * @param reg The SIP request to build. + */ + int eXosip_register_build_register(int rid, int expires, osip_message_t **reg); + +/** + * Send a REGISTER request for an existing registration. + * + * @param rid A unique identifier for the registration context + * @param reg The SIP request to build. (NULL for default REGISTER) + */ + int eXosip_register_send_register(int rid, osip_message_t *reg); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eXosip2/eX_setup.h b/include/eXosip2/eX_setup.h new file mode 100644 index 0000000000000000000000000000000000000000..d6681cc5523ddad0926d74622851be86567a4d4c --- /dev/null +++ b/include/eXosip2/eX_setup.h @@ -0,0 +1,258 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EX_SETUP_H__ +#define __EX_SETUP_H__ + +#include <osipparser2/osip_parser.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file eX_setup.h + * @brief eXosip setup API + * + * This file provide the API needed to setup and configure + * the SIP endpoint. + * + */ + +/** + * @defgroup eXosip2_conf eXosip2 configuration API + * @ingroup eXosip2_setup + * @{ + */ + +/** + * Initiate the eXtented oSIP library. + * + */ + int eXosip_init(void); + +/** + * Release ressource used by the eXtented oSIP library. + * + */ + void eXosip_quit(void); + +typedef enum { + EXOSIP_OPT_UDP_KEEP_ALIVE = 1, + EXOSIP_OPT_UDP_LEARN_PORT = 2, + EXOSIP_OPT_SET_HTTP_TUNNEL_PORT = 3, + EXOSIP_OPT_SET_HTTP_TUNNEL_PROXY = 4, + EXOSIP_OPT_SET_HTTP_OUTBOUND_PROXY = 5 /* used for http tunnel ONLY */ +} eXosip_option; + +/** + * Set eXosip options. + * See eXosip_option for available options. + * + * @param opt option to configure. + * @param value value for options. + * + */ +int eXosip_set_option(eXosip_option opt, void *value); + +/** + * Lock the eXtented oSIP library. + * + */ + int eXosip_lock(void); + +/** + * UnLock the eXtented oSIP library. + * + */ + int eXosip_unlock(void); + +/** + * Listen on a specified socket. + * + * @param transport IPPROTO_UDP for udp. (soon to come: TCP/TLS?) + * @param addr the address to bind (NULL for all interface) + * @param port the listening port. (0 for random port) + * @param family the IP family (AF_INET or AF_INET6). + * @param secure 0 for UDP or TCP, 1 for TLS (with TCP). + */ + int eXosip_listen_addr(int transport, const char *addr, int port, int family, + int secure); + +/** + * Listen on a specified socket. + * + * @param transport IPPROTO_UDP for udp. (soon to come: TCP/TLS?) + * @param socket socket to use for listening to UDP sip messages. + * @param port the listening port for masquerading. + */ + int eXosip_set_socket(int transport, int socket, int port); + +/** + * Set the SIP User-Agent: header string. + * + * @param user_agent the User-Agent header to insert in messages. + */ + void eXosip_set_user_agent(const char *user_agent); + +/** + * Use IPv6 instead of IPv4. + * + * @param ipv6_enable This paramter should be set to 1 to enable IPv6 mode. + */ + void eXosip_enable_ipv6(int ipv6_enable); + +/** + * This method is used to replace contact address with + * the public address of your NAT. The ip address should + * be retreived manually (fixed IP address) or with STUN. + * This address will only be used when the remote + * correspondant appears to be on an DIFFERENT LAN. + * + * @param public_address the ip address. + * + * If set to NULL, then the local ip address will be guessed + * automatically (returns to default mode). + */ + void eXosip_masquerade_contact(const char *public_address, int port); + +#ifndef DOXYGEN + +/** + * Force eXosip to use a specific ip address in all + * contact and Via headers in SIP message. + * **PLEASE DO NOT USE: use eXosip_masquerade_contact instead** + * + * @param localip the ip address. + * + * If set to NULL, then the local ip address will be guessed + * automatically (returns to default mode). + * + * ******LINPHONE specific methods****** + * + */ +int eXosip_force_masquerade_contact(const char *localip); + +/** + * Wake Up the eXosip_event_wait method. + * + */ + void __eXosip_wakeup_event(void); + +#define REMOVE_ELEMENT(first_element, element) \ + if (element->parent==NULL) \ + { first_element = element->next; \ + if (first_element!=NULL) \ + first_element->parent = NULL; } \ + else \ + { element->parent->next = element->next; \ + if (element->next!=NULL) \ + element->next->parent = element->parent; \ + element->next = NULL; \ + element->parent = NULL; } + +#define ADD_ELEMENT(first_element, element) \ + if (first_element==NULL) \ + { \ + first_element = element; \ + element->next = NULL; \ + element->parent = NULL; \ + } \ + else \ + { \ + element->next = first_element; \ + element->parent = NULL; \ + element->next->parent = element; \ + first_element = element; \ + } + +#define APPEND_ELEMENT(type_of_element_t, first_element, element) \ + if (first_element==NULL) \ + { first_element = element; \ + element->next = NULL; /* useless */ \ + element->parent = NULL; /* useless */ } \ + else \ + { type_of_element_t *f; \ + for (f=first_element; f->next!=NULL; f=f->next) \ + { } \ + f->next = element; \ + element->parent = f; \ + element->next = NULL; \ + } + +#endif + +/** @} */ + + +/** + * @defgroup eXosip2_network eXosip2 network API + * @ingroup eXosip2_setup + * @{ + */ + +/** + * Modify the transport protocol used to send SIP message. + * + * @param msg The SIP message to modify + * @param transport transport protocol to use ("UDP", "TCP" or "TLS") + */ + int eXosip_transport_set(osip_message_t *msg, const char *transport); + +/** + * Find the current localip (interface with default route). + * + * @param family AF_INET or AF_INET6 + * @param address a string containing the local IP address. + * @param size The size of the string + */ + int eXosip_guess_localip(int family, char *address, int size); + +#ifndef DOXYGEN + +/** + * Find the interface to be used to reach the specified host. + * + * @param ip a string containing the local IP address. + * @param localip the local ip address to be used to reach host. + * + * You usually don't need this function at all. + * + * ******LINPHONE specific methods****** + * + */ +int eXosip_get_localip_for(const char *host, char *localip, int size); + +#endif + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eXosip2/eX_subscribe.h b/include/eXosip2/eX_subscribe.h new file mode 100644 index 0000000000000000000000000000000000000000..55a581a0cb21f024ed0893e25c82fcd6d592b443 --- /dev/null +++ b/include/eXosip2/eX_subscribe.h @@ -0,0 +1,189 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EX_SUBSCRIBE_H__ +#define __EX_SUBSCRIBE_H__ + +#include <osipparser2/osip_parser.h> +#include <time.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file eX_subscribe.h + * @brief eXosip subscribe request API + * + * This file provide the API needed to control SUBSCRIBE requests. You can + * use it to: + * + * <ul> + * <li>build SUBSCRIBE requests.</li> + * <li>send SUBSCRIBE requests.</li> + * <li>build SUBSCRIBE answers.</li> + * <li>send SUBSCRIBE answers.</li> + * </ul> + */ + +/** + * @defgroup eXosip2_subscribe eXosip2 SUBSCRIBE and outgoing subscriptions + * @ingroup eXosip2_msg + * @{ + */ + +typedef enum eXosip_ss { + EXOSIP_SUBCRSTATE_UNKNOWN, /**< unknown subscription-state */ + EXOSIP_SUBCRSTATE_PENDING, /**< pending subscription-state */ + EXOSIP_SUBCRSTATE_ACTIVE, /**< active subscription-state */ + EXOSIP_SUBCRSTATE_TERMINATED /**< terminated subscription-state */ +} eXosip_ss_t; + +typedef enum eXosip_ss_reason { + DEACTIVATED, /**< deactivated for subscription-state */ + PROBATION, /**< probation for subscription-state */ + REJECTED, /**< rejected for subscription-state */ + TIMEOUT, /**< timeout for subscription-state */ + GIVEUP, /**< giveup for subscription-state */ + NORESOURCE /**< noresource for subscription-state */ +} eXosip_ss_reason_t; + + +typedef enum eXosip_ss_status { + EXOSIP_NOTIFY_UNKNOWN, /**< unknown state for subscription */ + EXOSIP_NOTIFY_PENDING, /**< subscription not yet accepted */ + EXOSIP_NOTIFY_ONLINE, /**< online status */ + EXOSIP_NOTIFY_BUSY, /**< busy status */ + EXOSIP_NOTIFY_BERIGHTBACK, /**< be right back status */ + EXOSIP_NOTIFY_AWAY, /**< away status */ + EXOSIP_NOTIFY_ONTHEPHONE, /**< on the phone status */ + EXOSIP_NOTIFY_OUTTOLUNCH, /**< out to lunch status */ + EXOSIP_NOTIFY_CLOSED /**< closed status */ +} eXosip_ss_status_t; + +/** + * Build a default initial SUBSCRIBE request. + * + * @param subscribe Pointer for the SIP request to build. + * @param to SIP url for callee. + * @param from SIP url for caller. + * @param route Route header for SUBSCRIBE. (optionnal) + * @param event Event header for SUBSCRIBE. + * @param expires Expires header for SUBSCRIBE. + */ + int eXosip_subscribe_build_initial_request(osip_message_t **subscribe, + const char *to, const char *from, + const char *route, const char *event, + int expires); + +/** + * Send an initial SUBSCRIBE request. + * + * @param subscribe SIP SUBSCRIBE message to send. + */ + int eXosip_subscribe_send_initial_request(osip_message_t *subscribe); + +/** + * Build a default new SUBSCRIBE message. + * + * @param did identifier of the subscription. + * @param sub Pointer for the SIP request to build. + */ + int eXosip_subscribe_build_refresh_request(int did, osip_message_t **sub); + +/** + * Send a new SUBSCRIBE request. + * + * @param did identifier of the subscription. + * @param sub SIP SUBSCRIBE message to send. + */ + int eXosip_subscribe_send_refresh_request(int did, osip_message_t *sub); + +/** @} */ + +/** + * @defgroup eXosip2_notify eXosip2 SUBSCRIBE and incoming subscriptions + * @ingroup eXosip2_msg + * @{ + */ + +/** + * Build answer for an SUBSCRIBE request. + * + * @param tid id of SUBSCRIBE transaction. + * @param status status for SIP answer to build. + * @param answer The SIP answer to build. + */ + int eXosip_insubscription_build_answer(int tid, int status, + osip_message_t **answer); + +/** + * Send answer for an SUBSCRIBE request. + * + * @param tid id of SUBSCRIBE transaction. + * @param status status for SIP answer to send. + * @param answer The SIP answer to send. (default will be sent if NULL) + */ + int eXosip_insubscription_send_answer(int tid, int status, + osip_message_t *answer); + +/** + * Build a request within subscription. + * + * @param did id of incoming subscription. + * @param method request method to build. + * @param request The SIP request to build. + */ + int eXosip_insubscription_build_request(int did, const char *method, + osip_message_t **request); + +/** + * Build a NOTIFY request within subscription. + * + * @param did id of incoming subscription. + * @param subscription_status subscription status (pending, active, terminated) + * @param subscription_reason subscription reason + * @param request The SIP request to build. + */ + int eXosip_insubscription_build_notify(int did, int subscription_status, + int subscription_reason, + osip_message_t **request); + +/** + * Send a request within subscription. + * + * @param did id of incoming subscription. + * @param request The SIP request to send. + */ + int eXosip_insubscription_send_request(int did, osip_message_t *request); + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/eXosip2/eXosip.h b/include/eXosip2/eXosip.h new file mode 100644 index 0000000000000000000000000000000000000000..a66cbeda236b97d2eb32b4b452cbf422e01482c7 --- /dev/null +++ b/include/eXosip2/eXosip.h @@ -0,0 +1,301 @@ +/* + eXosip - This is the eXtended osip library. + Copyright (C) 2002,2003,2004,2005 Aymeric MOIZARD - jack@atosc.org + + eXosip is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + eXosip is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifdef ENABLE_MPATROL +#include <mpatrol.h> +#endif + +#ifndef __EXOSIP_H__ +#define __EXOSIP_H__ + +#include <eXosip2/eX_setup.h> +#include <eXosip2/eX_register.h> +#include <eXosip2/eX_call.h> +#include <eXosip2/eX_options.h> +#include <eXosip2/eX_subscribe.h> +#include <eXosip2/eX_refer.h> +#include <eXosip2/eX_message.h> +#include <eXosip2/eX_publish.h> + +#include <osipparser2/osip_parser.h> +#include <osipparser2/sdp_message.h> +#include <time.h> + +/** + * @file eXosip.h + * @brief eXosip API + * + * eXosip is a high layer library for rfc3261: the SIP protocol. + * It offers a simple API to make it easy to use. eXosip2 offers + * great flexibility for implementing SIP endpoint like: + * <ul> + * <li>SIP User-Agents</li> + * <li>SIP Voicemail or IVR</li> + * <li>SIP B2BUA</li> + * <li>any SIP server acting as an endpoint (music server...)</li> + * </ul> + * + * If you need to implement proxy or complex SIP applications, + * you should consider using osip instead. + * + * Here are the eXosip capabilities: + * <pre> + * REGISTER to handle registration. + * INVITE/BYE to start/stop VoIP sessions. + * INFO to send DTMF within a VoIP sessions. + * OPTIONS to simulate VoIP sessions. + * re-INVITE to modify VoIP sessions + * REFER/NOTIFY to transfer calls. + * MESSAGE to send Instant Message. + * SUBSCRIBE/NOTIFY to handle presence capabilities. + * </pre> + * <P> + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * @defgroup eXosip2_authentication eXosip2 authentication API + * @ingroup eXosip2_msg + * @{ + */ + +/** + * Add authentication credentials. These are used when an outgoing + * request comes back with an authorization required response. + * + * @param username username + * @param userid login (usually equals the username) + * @param passwd password + * @param ha1 currently ignored + * @param realm realm within which credentials apply, or NULL + * to apply credentials to unrecognized realms + */ + int eXosip_add_authentication_info(const char *username, const char *userid, + const char *passwd, const char *ha1, + const char *realm); + +/** + * Clear all authentication credentials stored in eXosip. + * + */ + int eXosip_clear_authentication_info(void); + +/** + * Initiate some automatic actions: + * + * Retry with credentials upon reception of 401/407. + * Refresh REGISTER and SUBSCRIBE before the expiration delay. + * Retry with Contact header upon reception of 3xx request. + * + */ + void eXosip_automatic_action(void); + +/** @} */ + + +/** + * @defgroup eXosip2_sdp eXosip2 SDP helper API. + * @ingroup eXosip2_msg + * @{ + */ + +/** + * Get remote SDP body for the latest INVITE of call. + * + * @param did dialog id of call. + */ + sdp_message_t *eXosip_get_remote_sdp(int did); + +/** + * Get local SDP body for the latest INVITE of call. + * + * @param did dialog id of call. + */ + sdp_message_t *eXosip_get_local_sdp(int did); + +/** + * Get local SDP body for the given message. + * + * @param message message containing the SDP. + */ + sdp_message_t *eXosip_get_sdp_info(osip_message_t *message); + +/** + * Get audio connection information for call. + * + * @param sdp sdp information. + */ + sdp_connection_t *eXosip_get_audio_connection(sdp_message_t *sdp); + +/** + * Get audio media information for call. + * + * @param sdp sdp information. + */ + sdp_media_t *eXosip_get_audio_media(sdp_message_t *sdp); + +/** @} */ + +/** + * @defgroup eXosip2_event eXosip2 event API + * @ingroup eXosip2_setup + * @{ + */ + +/** + * Structure for event type description + * @var eXosip_event_type + */ + typedef enum eXosip_event_type + { + /* REGISTER related events */ + EXOSIP_REGISTRATION_NEW, /**< announce new registration. */ + EXOSIP_REGISTRATION_SUCCESS, /**< user is successfully registred. */ + EXOSIP_REGISTRATION_FAILURE, /**< user is not registred. */ + EXOSIP_REGISTRATION_REFRESHED, /**< registration has been refreshed. */ + EXOSIP_REGISTRATION_TERMINATED, /**< UA is not registred any more. */ + + /* INVITE related events within calls */ + EXOSIP_CALL_INVITE, /**< announce a new call */ + EXOSIP_CALL_REINVITE, /**< announce a new INVITE within call */ + + EXOSIP_CALL_NOANSWER, /**< announce no answer within the timeout */ + EXOSIP_CALL_PROCEEDING, /**< announce processing by a remote app */ + EXOSIP_CALL_RINGING, /**< announce ringback */ + EXOSIP_CALL_ANSWERED, /**< announce start of call */ + EXOSIP_CALL_REDIRECTED, /**< announce a redirection */ + EXOSIP_CALL_REQUESTFAILURE, /**< announce a request failure */ + EXOSIP_CALL_SERVERFAILURE, /**< announce a server failure */ + EXOSIP_CALL_GLOBALFAILURE, /**< announce a global failure */ + EXOSIP_CALL_ACK, /**< ACK received for 200ok to INVITE */ + + EXOSIP_CALL_CANCELLED, /**< announce that call has been cancelled */ + EXOSIP_CALL_TIMEOUT, /**< announce that call has failed */ + + /* request related events within calls (except INVITE) */ + EXOSIP_CALL_MESSAGE_NEW, /**< announce new incoming MESSAGE. */ + EXOSIP_CALL_MESSAGE_PROCEEDING, /**< announce a 1xx for MESSAGE. */ + EXOSIP_CALL_MESSAGE_ANSWERED, /**< announce a 200ok */ + EXOSIP_CALL_MESSAGE_REDIRECTED, /**< announce a failure. */ + EXOSIP_CALL_MESSAGE_REQUESTFAILURE, /**< announce a failure. */ + EXOSIP_CALL_MESSAGE_SERVERFAILURE, /**< announce a failure. */ + EXOSIP_CALL_MESSAGE_GLOBALFAILURE, /**< announce a failure. */ + + EXOSIP_CALL_CLOSED, /**< a BYE was received for this call */ + + /* for both UAS & UAC events */ + EXOSIP_CALL_RELEASED, /**< call context is cleared. */ + + /* response received for request outside calls */ + EXOSIP_MESSAGE_NEW, /**< announce new incoming MESSAGE. */ + EXOSIP_MESSAGE_PROCEEDING, /**< announce a 1xx for MESSAGE. */ + EXOSIP_MESSAGE_ANSWERED, /**< announce a 200ok */ + EXOSIP_MESSAGE_REDIRECTED, /**< announce a failure. */ + EXOSIP_MESSAGE_REQUESTFAILURE, /**< announce a failure. */ + EXOSIP_MESSAGE_SERVERFAILURE, /**< announce a failure. */ + EXOSIP_MESSAGE_GLOBALFAILURE, /**< announce a failure. */ + + /* Presence and Instant Messaging */ + EXOSIP_SUBSCRIPTION_UPDATE, /**< announce incoming SUBSCRIBE. */ + EXOSIP_SUBSCRIPTION_CLOSED, /**< announce end of subscription. */ + + EXOSIP_SUBSCRIPTION_NOANSWER, /**< announce no answer */ + EXOSIP_SUBSCRIPTION_PROCEEDING, /**< announce a 1xx */ + EXOSIP_SUBSCRIPTION_ANSWERED, /**< announce a 200ok */ + EXOSIP_SUBSCRIPTION_REDIRECTED, /**< announce a redirection */ + EXOSIP_SUBSCRIPTION_REQUESTFAILURE, /**< announce a request failure */ + EXOSIP_SUBSCRIPTION_SERVERFAILURE, /**< announce a server failure */ + EXOSIP_SUBSCRIPTION_GLOBALFAILURE, /**< announce a global failure */ + EXOSIP_SUBSCRIPTION_NOTIFY, /**< announce new NOTIFY request */ + + EXOSIP_SUBSCRIPTION_RELEASED, /**< call context is cleared. */ + + EXOSIP_IN_SUBSCRIPTION_NEW, /**< announce new incoming SUBSCRIBE.*/ + EXOSIP_IN_SUBSCRIPTION_RELEASED, /**< announce end of subscription. */ + + EXOSIP_EVENT_COUNT /**< MAX number of events */ + } eXosip_event_type_t; + +/** + * Structure for event description. + * @var eXosip_event_t + */ + typedef struct eXosip_event eXosip_event_t; + +/** + * Structure for event description + * @struct eXosip_event + */ + struct eXosip_event + { + eXosip_event_type_t type; /**< type of the event */ + char textinfo[256]; /**< text description of event */ + void *external_reference; /**< external reference (for calls) */ + + osip_message_t *request; /**< request within current transaction */ + osip_message_t *response; /**< last response within current transaction */ + osip_message_t *ack; /**< ack within current transaction */ + + int tid; /**< unique id for transactions (to be used for answers) */ + int did; /**< unique id for SIP dialogs */ + + int rid; /**< unique id for registration */ + int cid; /**< unique id for SIP calls (but multiple dialogs!) */ + int sid; /**< unique id for outgoing subscriptions */ + int nid; /**< unique id for incoming subscriptions */ + + int ss_status; /**< current Subscription-State for subscription */ + int ss_reason; /**< current Reason status for subscription */ + }; + +/** + * Free ressource in an eXosip event. + * + * @param je event to work on. + */ +void eXosip_event_free(eXosip_event_t *je); + +/** + * Wait for an eXosip event. + * + * @param tv_s timeout value (seconds). + * @param tv_ms timeout value (mseconds). + */ +eXosip_event_t *eXosip_event_wait(int tv_s, int tv_ms); + + +/** + * Wait for next eXosip event. + * + */ +eXosip_event_t *eXosip_event_get(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ltmain.sh b/ltmain.sh index 1a224ac2ae0c9bb7598f1aaa9bd7f2d4f6bdfb6a..9be0eb1c38c2db306bd70075c0b78a49d842ebf4 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -1,7 +1,7 @@ # ltmain.sh - Provide generalized library-building support services. # NOTE: Changing this file will not affect anything until you rerun configure. # -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 # Free Software Foundation, Inc. # Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 # @@ -17,7 +17,7 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -43,9 +43,14 @@ EXIT_FAILURE=1 PROGRAM=ltmain.sh PACKAGE=libtool -VERSION=1.5.6 -TIMESTAMP=" (1.1220.2.95 2004/04/11 05:50:42) Debian$Rev: 224 $" +VERSION=1.5.16 +TIMESTAMP=" (1.1220.2.235 2005/04/25 18:13:26)" +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes. +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi # Check that we have a working $echo. if test "X$1" = X--no-reexec; then @@ -107,8 +112,9 @@ if test "${LANG+set}" = set; then fi # Make sure IFS has a sensible default -: ${IFS=" -"} +lt_nl=' +' +IFS=" $lt_nl" if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then $echo "$modename: not configured to build any kind of library" 1>&2 @@ -127,6 +133,7 @@ show_help= execute_dlfiles= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" +quote_scanset='[[~#^*{};<>?'"'"' ]' ##################################### # Shell function definitions: @@ -138,7 +145,8 @@ o2lo="s/\\.${objext}\$/.lo/" # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. -func_win32_libid () { +func_win32_libid () +{ win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in @@ -178,12 +186,13 @@ func_win32_libid () { # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' -func_infer_tag () { +func_infer_tag () +{ if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -204,7 +213,7 @@ func_infer_tag () { for arg in $CC; do # Double-quote args containing other shell metacharacters. case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -235,6 +244,108 @@ func_infer_tag () { esac fi } + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 + exit $EXIT_FAILURE + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xdir="$my_gentop/$my_xlib" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + status=$? + if test "$status" -ne 0 && test ! -d "$my_xdir"; then + exit $status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} # End of Shell function definitions ##################################### @@ -305,10 +416,10 @@ do --version) $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" $echo - $echo "Copyright (C) 2003 Free Software Foundation, Inc." + $echo "Copyright (C) 2005 Free Software Foundation, Inc." $echo "This is free software; see the source for copying conditions. There is NO" $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - exit $EXIT_SUCCESS + exit $? ;; --config) @@ -317,7 +428,7 @@ do for tagname in $taglist; do ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" done - exit $EXIT_SUCCESS + exit $? ;; --debug) @@ -342,7 +453,7 @@ do else $echo "disable static libraries" fi - exit $EXIT_SUCCESS + exit $? ;; --finish) mode="finish" ;; @@ -399,7 +510,7 @@ if test -z "$show_help"; then # Infer the operation mode. if test -z "$mode"; then $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 - $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 case $nonopt in *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) mode=link @@ -516,7 +627,7 @@ if test -z "$show_help"; then # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -547,8 +658,11 @@ if test -z "$show_help"; then case $lastarg in # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") lastarg="\"$lastarg\"" ;; esac @@ -621,6 +735,15 @@ if test -z "$show_help"; then esac done + qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` + case $qlibobj in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + qlibobj="\"$qlibobj\"" ;; + esac + if test "X$libobj" != "X$qlibobj"; then + $echo "$modename: libobj name \`$libobj' may not contain shell special characters." + exit $EXIT_FAILURE + fi objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$obj"; then @@ -693,12 +816,17 @@ compiler." $run $rm $removelist exit $EXIT_FAILURE fi - $echo $srcfile > "$lockfile" + $echo "$srcfile" > "$lockfile" fi if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi + qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` + case $qsrcfile in + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") + qsrcfile="\"$qsrcfile\"" ;; + esac $run $rm "$libobj" "${libobj}T" @@ -720,10 +848,10 @@ EOF fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then - command="$base_compile $srcfile $pic_flag" + command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code - command="$base_compile $srcfile" + command="$base_compile $qsrcfile" fi if test ! -d "${xdir}$objdir"; then @@ -803,9 +931,9 @@ EOF if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code - command="$base_compile $srcfile" + command="$base_compile $qsrcfile" else - command="$base_compile $srcfile $pic_flag" + command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then command="$command -o $obj" @@ -983,7 +1111,7 @@ EOF arg="$1" shift case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test ;; *) qarg=$arg ;; @@ -1227,6 +1355,11 @@ EOF prev= continue ;; + darwin_framework) + compiler_flags="$compiler_flags $arg" + prev= + continue + ;; *) eval "$prev=\"\$arg\"" prev= @@ -1285,6 +1418,12 @@ EOF continue ;; + -framework) + prev=darwin_framework + compiler_flags="$compiler_flags $arg" + continue + ;; + -inst-prefix-dir) prev=inst_prefix continue @@ -1345,7 +1484,7 @@ EOF # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; - *-*-openbsd* | *-*-freebsd*) + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; @@ -1356,7 +1495,7 @@ EOF esac elif test "X$arg" = "X-lc_r"; then case $host in - *-*-openbsd* | *-*-freebsd*) + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; @@ -1366,8 +1505,20 @@ EOF continue ;; + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) - deplibs="$deplibs $arg" + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" continue ;; @@ -1376,18 +1527,19 @@ EOF continue ;; - # gcc -m* arguments should be passed to the linker via $compiler_flags - # in order to pass architecture information to the linker - # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo - # but this is not reliable with gcc because gcc may use -mfoo to - # select a different linker, different libraries, etc, while - # -Wl,-mfoo simply passes -mfoo to the linker. - -m*) + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*) + # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -1503,7 +1655,7 @@ EOF for flag in $args; do IFS="$save_ifs" case $flag in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") flag="\"$flag\"" ;; esac @@ -1521,7 +1673,7 @@ EOF for flag in $args; do IFS="$save_ifs" case $flag in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") flag="\"$flag\"" ;; esac @@ -1554,7 +1706,7 @@ EOF # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -1688,7 +1840,7 @@ EOF # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -1838,10 +1990,7 @@ EOF case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; - link) - libs="$deplibs %DEPLIBS%" - test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" - ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$pass" = dlopen; then @@ -1858,7 +2007,7 @@ EOF compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else - deplibs="$deplib $deplibs" + compiler_flags="$compiler_flags $deplib" fi continue ;; @@ -1977,7 +2126,22 @@ EOF fi case $linkmode in lib) - if test "$deplibs_check_method" != pass_all; then + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then $echo $echo "*** Warning: Trying to link with static lib archive $deplib." $echo "*** I have the capability to make that library automatically link in when" @@ -2051,6 +2215,8 @@ EOF # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no + avoidtemprpath= + # Read the .la file case $lib in @@ -2149,11 +2315,19 @@ EOF dir="$libdir" absdir="$libdir" fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else - dir="$ladir/$objdir" - absdir="$abs_ladir/$objdir" - # Remove this search path later - notinst_path="$notinst_path $abs_ladir" + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi fi # $installed = yes name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` @@ -2226,7 +2400,7 @@ EOF if test -n "$library_names" && { test "$prefer_static_libs" = no || test -z "$old_library"; }; then # We need to hardcode the library path - if test -n "$shlibpath_var"; then + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath " in *" $dir "*) ;; @@ -2670,12 +2844,12 @@ EOF *) continue ;; esac case " $deplibs " in - *" $depdepl "*) ;; - *) deplibs="$depdepl $deplibs" ;; + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; esac case " $deplibs " in - *" $path "*) ;; - *) deplibs="$deplibs $path" ;; + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; esac done fi # link_all_deplibs != no @@ -2929,11 +3103,6 @@ EOF age="$number_minor" revision="$number_minor" ;; - *) - $echo "$modename: unknown library version type \`$version_type'" 1>&2 - $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit $EXIT_FAILURE - ;; esac ;; no) @@ -2947,7 +3116,7 @@ EOF case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) - $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; @@ -2956,7 +3125,7 @@ EOF case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) - $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; @@ -2965,7 +3134,7 @@ EOF case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) - $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; @@ -2991,7 +3160,7 @@ EOF versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... minor_current=`expr $current + 1` - verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" ;; freebsd-aout) @@ -3197,7 +3366,7 @@ EOF *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; - *-*-openbsd* | *-*-freebsd*) + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; @@ -3679,67 +3848,13 @@ EOF eval libobjs=\"\$libobjs $whole_archive_flag_spec\" else gentop="$output_objdir/${outputname}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "$mkdir $gentop" - $run $mkdir "$gentop" - status=$? - if test "$status" -ne 0 && test ! -d "$gentop"; then - exit $status - fi generated="$generated $gentop" - for xlib in $convenience; do - # Extract the objects. - case $xlib in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "$mkdir $xdir" - $run $mkdir "$xdir" - status=$? - if test "$status" -ne 0 && test ! -d "$xdir"; then - exit $status - fi - # We will extract separately just the conflicting names and we will no - # longer touch any unique names. It is faster to leave these extract - # automatically by $AR in one run. - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 - $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 - $AR t "$xabs" | sort | uniq -cd | while read -r count name - do - i=1 - while test "$i" -le "$count" - do - # Put our $i before any first dot (extension) - # Never overwrite any file - name_to="$name" - while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" - do - name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` - done - $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" - $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? - i=`expr $i + 1` - done - done - fi - - libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` - done + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" fi fi - + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" @@ -3788,6 +3903,7 @@ EOF save_libobjs=$libobjs fi save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` # Clear the reloadable object creation command queue and # initialize k to one. @@ -3797,7 +3913,7 @@ EOF delfiles= last_robj= k=1 - output=$output_objdir/$save_output-${k}.$objext + output=$output_objdir/$output_la-${k}.$objext # Loop over the list of objects to be linked. for obj in $save_libobjs do @@ -3817,9 +3933,9 @@ EOF # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" fi - last_robj=$output_objdir/$save_output-${k}.$objext + last_robj=$output_objdir/$output_la-${k}.$objext k=`expr $k + 1` - output=$output_objdir/$save_output-${k}.$objext + output=$output_objdir/$output_la-${k}.$objext objlist=$obj len=1 fi @@ -3839,13 +3955,13 @@ EOF eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" fi - # Set up a command to remove the reloadale object files + # Set up a command to remove the reloadable object files # after they are used. i=0 while test "$i" -lt "$k" do i=`expr $i + 1` - delfiles="$delfiles $output_objdir/$save_output-${i}.$objext" + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" done $echo "creating a temporary reloadable object file: $output" @@ -3977,64 +4093,10 @@ EOF eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" else gentop="$output_objdir/${obj}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "$mkdir $gentop" - $run $mkdir "$gentop" - status=$? - if test "$status" -ne 0 && test ! -d "$gentop"; then - exit $status - fi generated="$generated $gentop" - for xlib in $convenience; do - # Extract the objects. - case $xlib in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "$mkdir $xdir" - $run $mkdir "$xdir" - status=$? - if test "$status" -ne 0 && test ! -d "$xdir"; then - exit $status - fi - # We will extract separately just the conflicting names and we will no - # longer touch any unique names. It is faster to leave these extract - # automatically by $AR in one run. - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 - $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 - $AR t "$xabs" | sort | uniq -cd | while read -r count name - do - i=1 - while test "$i" -le "$count" - do - # Put our $i before any first dot (extension) - # Never overwrite any file - name_to="$name" - while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" - do - name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` - done - $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" - $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? - i=`expr $i + 1` - done - done - fi - - reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` - done + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi @@ -4296,12 +4358,12 @@ extern \"C\" { # Prepare the list of exported symbols if test -z "$export_symbols"; then - export_symbols="$output_objdir/$output.exp" + export_symbols="$output_objdir/$outputname.exp" $run $rm $export_symbols $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' else - $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' - $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval "${SED} -e 's/\([ ][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' $run eval 'mv "$nlist"T "$nlist"' fi fi @@ -4353,7 +4415,26 @@ extern \"C\" { #endif /* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ const char *name; lt_ptr address; } @@ -4582,7 +4663,7 @@ static const void *lt_preloaded_setup() { esac case $host in *cygwin* | *mingw* ) - cwrappersource=`$echo ${objdir}/lt-${output}.c` + cwrappersource=`$echo ${objdir}/lt-${outputname}.c` cwrapper=`$echo ${output}.exe` $rm $cwrappersource $cwrapper trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 @@ -4815,7 +4896,7 @@ sed_quote_subst='$sed_quote_subst' # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. -if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" @@ -4992,71 +5073,73 @@ fi\ if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "$mkdir $gentop" - $run $mkdir "$gentop" - status=$? - if test "$status" -ne 0 && test ! -d "$gentop"; then - exit $status - fi generated="$generated $gentop" - # Add in members from convenience archives. - for xlib in $addlibs; do - # Extract the objects. - case $xlib in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "$mkdir $xdir" - $run $mkdir "$xdir" - status=$? - if test "$status" -ne 0 && test ! -d "$xdir"; then - exit $status - fi - # We will extract separately just the conflicting names and we will no - # longer touch any unique names. It is faster to leave these extract - # automatically by $AR in one run. - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 - $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 - $AR t "$xabs" | sort | uniq -cd | while read -r count name - do - i=1 - while test "$i" -le "$count" - do - # Put our $i before any first dot (extension) - # Never overwrite any file - name_to="$name" - while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" - do - name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` - done - $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" - $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? - i=`expr $i + 1` - done - done - fi - - oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` - done + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "copying selected object files to avoid basename conflicts..." + + if test -z "$gentop"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + status=$? + if test "$status" -ne 0 && test ! -d "$gentop"; then + exit $status + fi + fi + + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + counter=`expr $counter + 1` + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + $run ln "$obj" "$gentop/$newobj" || + $run cp "$obj" "$gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" if len=`expr "X$cmds" : ".*"` && @@ -5070,20 +5153,7 @@ fi\ objlist= concat_cmds= save_oldobjs=$oldobjs - # GNU ar 2.10+ was changed to match POSIX; thus no paths are - # encoded into archives. This makes 'ar r' malfunction in - # this piecewise linking case whenever conflicting object - # names appear in distinct ar calls; check, warn and compensate. - if (for obj in $save_oldobjs - do - $echo "X$obj" | $Xsed -e 's%^.*/%%' - done | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2 - $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2 - AR_FLAGS=cq - fi + # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do @@ -5295,7 +5365,7 @@ relink_command=\"$relink_command\"" # Aesthetically quote it. arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -5311,7 +5381,7 @@ relink_command=\"$relink_command\"" # Aesthetically quote it. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -5359,7 +5429,7 @@ relink_command=\"$relink_command\"" # Aesthetically quote the argument. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + *$quote_scanset* | *]* | *\|* | *\&* | *\(* | *\)* | "") arg="\"$arg\"" ;; esac @@ -6398,7 +6468,7 @@ esac $echo $echo "Try \`$modename --help' for more information about other modes." -exit $EXIT_SUCCESS +exit $? # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting diff --git a/m4/Makefile.am b/m4/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..278ccdd862c0b84634df8f203620f6c643606a16 --- /dev/null +++ b/m4/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST=speex.m4 osip.m4 exosip.m4 ilbc.m4 diff --git a/m4/acx_pthread.m4 b/m4/acx_pthread.m4 new file mode 100644 index 0000000000000000000000000000000000000000..ffc4ef417d37b8737b3c24293b5d4112847384d9 --- /dev/null +++ b/m4/acx_pthread.m4 @@ -0,0 +1,224 @@ +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl This macro figures out how to build C programs using POSIX +dnl threads. It sets the PTHREAD_LIBS output variable to the threads +dnl library and linker flags, and the PTHREAD_CFLAGS output variable +dnl to any special C compiler flags that are needed. (The user can also +dnl force certain compiler flags/libs to be tested by setting these +dnl environment variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl If you are only building threads programs, you may wish to +dnl use these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE +dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands +dnl to run it if it is not found. If ACTION-IF-FOUND is not specified, +dnl the default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, +dnl or if you have any other suggestions or comments. This macro was +dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org) +dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread +dnl macros posted by AFC to the autoconf macro repository. We are also +dnl grateful for the helpful feedback of numerous users. +dnl +dnl @version $Id$ +dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Alejandro Forero Cuervo <bachue@bachue.com> + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include <pthread.h>], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include <pthread.h>], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include <pthread.h>], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *solaris* | alpha*-osf*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi + +])dnl ACX_PTHREAD diff --git a/m4/exosip.m4 b/m4/exosip.m4 new file mode 100644 index 0000000000000000000000000000000000000000..f5ebdded8053a8778f8f8b4dddeb55287aadb03c --- /dev/null +++ b/m4/exosip.m4 @@ -0,0 +1,88 @@ +AC_DEFUN([LP_SETUP_EXOSIP],[ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([LP_CHECK_OSIP2]) + +dnl ********************************************************************* +dnl Source packaging numbers +EXOSIP_MAJOR_VERSION=1 +EXOSIP_MINOR_VERSION=9 +EXOSIP_MICRO_VERSION=1 + +SONAME_MAJOR_VERSION=5 +SONAME_MINOR_VERSION=0 +SONAME_MICRO_VERSION=0 + +dnl program extension +EXOSIP_VERSION=$EXOSIP_MAJOR_VERSION.$EXOSIP_MINOR_VERSION.$EXOSIP_MICRO_VERSION + +LIBEXOSIP_SO_VERSION=$SONAME_MAJOR_VERSION:$SONAME_MINOR_VERSION:$SONAME_MICRO_VERSION + +AC_SUBST(LIBEXOSIP_SO_VERSION, $LIBEXOSIP_SO_VERSION) +AC_SUBST(EXOSIP_VERSION) + +dnl support for linux-thread or posix thread (pthread.h) +AC_ARG_ENABLE(pthread, +[ --enable-pthread enable support for POSIX threads. (autodetect)], +enable_pthread=$enableval,enable_pthread="no") + +dnl compile with mt support +if test "x$enable_pthread" = "xyes"; then + EXOSIP_CFLAGS="-DHAVE_PTHREAD" + EXOSIP_LIBS="-lpthread" +else + ACX_PTHREAD() +fi + +dnl eXosip embeded stuff +EXOSIP_CFLAGS="$OSIP_CFLAGS -DOSIP_MT -DENABLE_TRACE -DNEW_TIMER -DSM -DMSN_SUPPORT -DUSE_TMP_BUFFER" +EXOSIP_LIBS="$OSIP_LIBS" +AC_CHECK_HEADERS(semaphore.h) +AC_CHECK_HEADERS(sys/sem.h) +case $target in + linux*) + EXOSIP_CFLAGS="$EXOSIP_CFLAGS -pedantic" + ;; + irix*) + ;; + hpux* | hp-ux*) + ;; + aix*) + ;; + osf*) + AC_CHECK_LIB(rt,sem_open,[EXOSIP_LIBS="$EXOSIP_LIBS -lrt"]) + ;; + sunos*) + ;; + darwin*) + EXOSIP_CFLAGS="$EXOSIP_CFLAGS -pedantic" + ;; + *) + ;; +esac + +AC_CHECK_LIB(posix4,sem_open,[EXOSIP_LIBS="$EXOSIP_LIBS -lposix4 -mt"]) +AC_CHECK_LIB(nsl,nis_add,[EXOSIP_LIBS="$EXOSIP_LIBS -lnsl"]) +AC_CHECK_LIB(socket,sendto,[EXOSIP_LIBS="$EXOSIP_LIBS -lsocket"]) +AC_CHECK_LIB(rt,clock_gettime,[EXOSIP_LIBS="$EXOSIP_LIBS -lrt"]) +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(ctype.h) +AC_CHECK_HEADERS(string.h) +AC_CHECK_HEADERS(strings.h) +AC_CHECK_HEADERS(stdio.h) +AC_CHECK_HEADERS(stdlib.h) +AC_CHECK_HEADERS(unistd.h) +AC_CHECK_HEADERS(stdarg.h) +AC_CHECK_HEADERS(varargs.h) +AC_CHECK_HEADERS(sys/time.h) +AC_CHECK_HEADERS(assert.h) +AC_CHECK_HEADERS(signal.h) +AC_CHECK_HEADERS(sys/signal.h) +AC_CHECK_HEADERS(malloc.h) +AC_CHECK_HEADERS(sys/select.h) +AC_CHECK_HEADERS(sys/types.h) +AC_CHECK_HEADERS(fcntl.h) + +AC_SUBST(EXOSIP_CFLAGS) +AC_SUBST(EXOSIP_LIBS) +]) diff --git a/m4/ilbc.m4 b/m4/ilbc.m4 new file mode 100644 index 0000000000000000000000000000000000000000..465f8506d7d740af4b5cbe40ac5b6b47bcea8067 --- /dev/null +++ b/m4/ilbc.m4 @@ -0,0 +1,33 @@ +AC_DEFUN([LP_CHECK_ILBC],[ + +AC_ARG_WITH( ilbc, + [ --with-ilbc Set prefix where ilbc headers and libs can be found (ex:/usr, /usr/local, none to disable ilbc support) [default=/usr] ], + [ ilbc_prefix=${withval}],[ ilbc_prefix="/usr" ]) + +if test "$ilbc_prefix" = "none" ; then + AC_MSG_NOTICE([iLBC codec support disabled. ]) +else + ILBC_CFLAGS=" -I${ilbc_prefix}/include/ilbc" + ILBC_LIBS="-L${ilbc_prefix}/lib -lilbc -lm" + CPPFLAGS_save=$CPPFLAGS + CPPFLAGS=$ILBC_CFLAGS + LDFLAGS_save=$LDFLAGS + LDFLAGS=$ILBC_LIBS + AC_CHECK_HEADERS(iLBC_decode.h,[AC_CHECK_LIB(ilbc,iLBC_decode,ilbc_found=yes,ilbc_found=no) + ],ilbc_found=no) + + CPPFLAGS=$CPPFLAGS_save + LDFLAGS=$LDFLAGS_save + + if test "$ilbc_found" = "no" ; then + AC_MSG_WARN([Could not find ilbc headers or libs. Please install ilbc package from http://www.linphone.org if you want iLBC codec support in linphone.]) + ILBC_CFLAGS= + ILBC_LIBS= + else + AC_DEFINE(HAVE_ILBC,1,[Defined when we have ilbc codec lib]) + AC_SUBST(ILBC_CFLAGS) + AC_SUBST(ILBC_LIBS) + fi +fi + +]) diff --git a/m4/osip.m4 b/m4/osip.m4 new file mode 100644 index 0000000000000000000000000000000000000000..6812524d872fcc088906e2c7d1de172902704db6 --- /dev/null +++ b/m4/osip.m4 @@ -0,0 +1,32 @@ +AC_DEFUN([LP_CHECK_OSIP2],[ + +AC_ARG_WITH( osip, + [ --with-osip Set prefix where osip can be found (ex:/usr or /usr/local)[default=/usr/local] ], + [ osip_prefix=${withval}],[ osip_prefix=/usr ]) +AC_SUBST(osip_prefix) + + +OSIP_CFLAGS="-I$osip_prefix/include" +OSIP_LIBS="-L$osip_prefix/lib" + +dnl check osip2 headers +CPPFLAGS_save=$CPPFLAGS +CPPFLAGS=$OSIP_CFLAGS +AC_CHECK_HEADER([osip2/osip.h], ,AC_MSG_ERROR([Could not find osip2 headers !])) +CPPFLAGS=$CPPFLAGS_save + +dnl check for osip2 libs +LDFLAGS_save=$LDFLAGS +LDFLAGS=$OSIP_LIBS +dnl AC_CHECK_LIB adds osipparser2 to LIBS, I don't want that ! +LIBS_save=$LIBS +AC_CHECK_LIB(osipparser2,osip_message_init, , AC_MSG_ERROR([Could not find osip2 libraries !])) +LDFLAGS=$LDFLAGS_save +LIBS=$LIBS_save + +OSIP_LIBS="$OSIP_LIBS -losipparser2 -losip2" + +AC_SUBST(OSIP_CFLAGS) +AC_SUBST(OSIP_LIBS) + +]) diff --git a/m4/speex.m4 b/m4/speex.m4 new file mode 100644 index 0000000000000000000000000000000000000000..884d5684b2e84dad3ff90fc76a8909586e7d4802 --- /dev/null +++ b/m4/speex.m4 @@ -0,0 +1,24 @@ +AC_DEFUN([LP_CHECK_SPEEX],[ +dnl only accept speex>=1.1.6 or 1.0.5 (the versions that have speex_encode_int ) +AC_ARG_WITH( speex, + [ --with-speex Set prefix where speex lib can be found (ex:/usr, /usr/local) [default=/usr] ], + [ speex_prefix=${withval}],[ speex_prefix="/usr" ]) + +SPEEX_CFLAGS=" -I${speex_prefix}/include -I${speex_prefix}/include/speex" +SPEEX_LIBS="-L${speex_prefix}/lib -lspeex -lm" +CPPFLAGS_save=$CPPFLAGS +CPPFLAGS=$SPEEX_CFLAGS +LDFLAGS_save=$LDFLAGS +LDFLAGS=$SPEEX_LIBS +AC_CHECK_HEADERS(speex.h,[AC_CHECK_LIB(speex,speex_encode_int,speex_found=yes,speex_found=no) +],speex_found=no) + +if test "$speex_found" = "no" ; then +AC_MSG_ERROR([Could not find a libspeex version that have the speex_encode_int() function. Please install libspeex=1.0.5 or libspeex>=1.1.6]) +fi + +AC_SUBST(SPEEX_CFLAGS) +AC_SUBST(SPEEX_LIBS) +CPPFLAGS=$CPPFLAGS_save +LDFLAGS=$LDFLAGS_save +]) diff --git a/m4/video.m4 b/m4/video.m4 new file mode 100644 index 0000000000000000000000000000000000000000..534277de1aa080ed1e396ea9280e0f30190e6326 --- /dev/null +++ b/m4/video.m4 @@ -0,0 +1,85 @@ +AC_DEFUN([LP_CHECK_DEP],[ + dnl $1=dependency description + dnl $2=dependency short name, will be suffixed with _CFLAGS and _LIBS + dnl $3=headers's place + dnl $4=lib's place + dnl $5=header to check + dnl $6=lib to check + dnl $7=function to check in library + + NAME=$2 + dep_headersdir=$3 + dep_libsdir=$4 + dep_header=$5 + dep_lib=$6 + dep_funclib=$7 + + eval ${NAME}_CFLAGS=\"-I $dep_headersdir \" + eval ${NAME}_LIBS=\"-L $dep_libsdir -l$dep_lib\" + + CPPFLAGS_save=$CPPFLAGS + LDFLAGS_save=$LDFLAGS + CPPFLAGS="-I $dep_headersdir " + LDFLAGS="-L $dep_libsdir " + + AC_CHECK_HEADERS([$dep_header],[AC_CHECK_LIB([$dep_lib],[$dep_funclib],found=yes,found=no) + ],found=no) + + if test "$found" = "yes" ; then + eval ${NAME}_found=yes + AC_DEFINE([HAVE_${NAME}],1,[Defined when we have found $1]) + AC_SUBST(${NAME}_CFLAGS) + AC_SUBST(${NAME}_LIBS) + else + eval ${NAME}_found=no + eval ${NAME}_CFLAGS= + eval ${NAME}_LIBS= + fi + CPPFLAGS=$CPPFLAGS_save + LDFLAGS=$LDFLAGS_save + +]) + + +AC_DEFUN([LP_CHECK_VIDEO],[ + + dnl conditionnal build of video support + AC_ARG_ENABLE(video, + [ --enable-video Turn on video support compiling: not functionnal for the moment], + [case "${enableval}" in + yes) video=true ;; + no) video=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-video) ;; + esac],[video=false]) + + AC_ARG_WITH( ffmpeg, + [ --with-ffmpeg Sets the installation prefix of ffmpeg, needed for video support. [default=/usr] ], + [ ffmpegdir=${withval}],[ ffmpegdir=/usr ]) + + AC_ARG_WITH( sdl, + [ --with-sdl Sets the installation prefix of libSDL, needed for video support. [default=/usr] ], + [ libsdldir=${withval}],[ libsdldir=/usr ]) + + if test "$video" = "true"; then + + dnl test for ffmpeg presence + LP_CHECK_DEP([ffmpeg],[FFMPEG],[${ffmpegdir}/include/ffmpeg],[${ffmpegdir}/lib],[avcodec.h],[avcodec],[avcodec_init]) + if test "$FFMPEG_found" = "no" ; then + AC_MSG_ERROR([Could not find ffmpeg headers and library. This is mandatory for video support]) + fi + + LP_CHECK_DEP([SDL],[SDL],[${libsdldir}/include],[${libsdldir}/lib],[SDL/SDL.h],[SDL],[SDL_Init]) + if test "$SDL_found" = "no" ; then + AC_MSG_ERROR([Could not find libsdl headers and library. This is mandatory for video support]) + fi + + VIDEO_CFLAGS=" $FFMPEG_CFLAGS $SDL_CFLAGS" + VIDEO_LIBS=" $FFMPEG_LIBS $SDL_LIBS" + + AC_DEFINE(VIDEO_ENABLED,1,[Set when video support is enabled]) + + fi + + AC_SUBST(VIDEO_CFLAGS) + AC_SUBST(VIDEO_LIBS) +]) diff --git a/src/Makefile.am b/src/Makefile.am index 9c497591a49be152bc0cea4039de059949ea5e1c..72a960941931155a163a0e356e6f89ea1cdcfd79 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,8 +22,8 @@ sflphoned_SOURCES = call.cpp eventthread.cpp main.cpp sipvoiplink.cpp voIPLi sflphoned_CXXFLAGS = -DPREFIX=\"$(prefix)\" -DPROGSHAREDIR=\"${datadir}/sflphone\" $(ZEROCONFFLAGS) #sflphoned_LDFLAGS = -static -sflphoned_LDADD = gui/libguiframework.la audio/libaudio.la ../stund/libstun.la ../utilspp/libutilspp.la -lpthread $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) config/libconfig.la +sflphoned_LDADD = gui/libguiframework.la audio/libaudio.la ../stund/libstun.la ../utilspp/libutilspp.la $(top_builddir)/exosip2/libeXosip2.la $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) config/libconfig.la #KDE_CXXFLAGS = $(USE_EXCEPTIONS) -AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir)/audio/pacpp/include $(libccext2_CFLAGS) $(libccgnu2_CFLAGS) $(portaudio_CFLAGS) +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(srcdir)/audio/pacpp/include $(libccext2_CFLAGS) $(libccgnu2_CFLAGS) $(portaudio_CFLAGS) noinst_HEADERS = observer.h diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am index 9306d347bff282cd73458eacff5f33b3c6595f8a..f095b0b8e4d04e84c4ea0e97150576c1a0ad3d3a 100644 --- a/src/audio/Makefile.am +++ b/src/audio/Makefile.am @@ -10,7 +10,7 @@ libaudio_la_SOURCES = alaw.cpp alaw.h audiocodec.cpp audiocodec.h \ tonegenerator.cpp tonegenerator.h ulaw.cpp ulaw.h tone.cpp tonelist.cpp audioloop.cpp \ audiofile.cpp -AM_CXXFLAGS = -I$(top_srcdir) -I$(srcdir)/pacpp/include/ $(libccext2_CFLAGS) $(libccrtp1_CFLAGS) $(portaudio_CFLAGS) +AM_CXXFLAGS = -I$(top_srcdir)/include -I$(srcdir)/pacpp/include/ $(libccext2_CFLAGS) $(libccrtp1_CFLAGS) $(portaudio_CFLAGS) libaudio_la_LIBADD = gsm/libgsm.la pacpp/source/portaudiocpp/libportaudiocpp.la noinst_HEADERS = tone.h tonelist.h audioloop.h audiofile.h