merged in commercial smqueue

This commit is contained in:
Michael Iedema 2014-03-25 00:58:33 +01:00
parent db01753ed4
commit 6914eeca7e
67 changed files with 2739 additions and 1489 deletions

4
.gitmodules vendored
View File

@ -10,3 +10,7 @@
path = sqlite3
url = git@github.com:RangeNetworks/sqlite3.git
branch = master
[submodule "NodeManager"]
path = NodeManager
url = git@github.com:RangeNetworks/NodeManager.git
branch = 4.0

@ -1 +1 @@
Subproject commit bd94d0a9883002daa8310b601f28eed3b0d87d2f
Subproject commit abec8dabb69f8f2bdefdb9bcca340b89f43ce419

View File

@ -1,6 +1,6 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -2,7 +2,7 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -2,7 +2,7 @@
@brief Call Control messages, GSM 04.08 9.3
*/
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2008, 2009, 2014 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
*

View File

@ -1,6 +1,6 @@
/**@file Elements for Call Control, GSM 04.08 10.5.4. */
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2008, 2009, 2014 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
*

View File

@ -2,9 +2,9 @@
@brief Elements for Mobility Management messages, GSM 04.08 9.2.
*/
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2008, 2014 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* Copyright 2014 Range Networks, Inc.
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.

View File

@ -3,6 +3,7 @@
/*
* Copyright 2008-2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2008, 2009, 2010, 2014 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008, 2010 Free Software Foundation, Inc.
* Copyright 2008, 2010, 2014 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2008, 2014 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2008, 2014 Free Software Foundation, Inc.
*
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
*
@ -387,7 +387,7 @@ class L2Frame : public BitVector {
bool M() const { return mStart[8*2+6] & 0x01; }
/** Return the L3 payload part. Assumes A or B header format. */
BitVector L3Part() const { return segment(8*3,8*L()); }
BitVector L3Part() const { return cloneSegment(8*3,8*L()); }
/** Return NR sequence number, GSM 04.06 3.5.2.4. Assumes A or B header. */
unsigned NR() const { return peekField(8*1+0,3); }

View File

@ -2,7 +2,7 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing

View File

@ -1,6 +1,6 @@
/**@file Global system parameters. */
/*
* Copyright 2008, 2009 Free Software Foundation, Inc.
* Copyright 2008, 2009, 2014 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under multiple licenses;

View File

@ -30,11 +30,11 @@ SUBDIRS = \
sqlite3 \
CommonLibs \
Globals \
SR \
GSM \
SMS \
doc \
tools \
NodeManager \
smqueue \
testing

View File

@ -24,23 +24,28 @@ SMS_INCLUDEDIR = $(top_srcdir)/SMS
GLOBALS_INCLUDEDIR = $(top_srcdir)/Globals
SQLITE_INCLUDEDIR = $(top_srcdir)/sqlite3
SR_INCLUDEDIR = $(top_srcdir)/SR
NODEMANAGER_INCLUDEDIR = $(top_srcdir)/NodeManager
JSONBOX_INCLUDEDIR = $(top_srcdir)/NodeManager/JsonBox-0.4.3/include
SVNDEV = -D'SVN_REV="$(shell svnversion -n $(top_builddir))"'
SVNDEV = -D'SVN_REV="$(shell svn info $(top_builddir) | grep "Last Changed Rev:" | cut -d " " -f 4) CommonLibs:rev$(shell svn info $(top_builddir)/CommonLibs | grep "Last Changed Rev:" | cut -d " " -f 4)"'
STD_DEFINES_AND_INCLUDES = \
$(SVNDEV) \
-DSR_API_ONLY \
-I$(COMMON_INCLUDEDIR) \
-I$(GSM_INCLUDEDIR) \
-I$(SMS_INCLUDEDIR) \
-I$(GLOBALS_INCLUDEDIR) \
-I$(SR_INCLUDEDIR) \
-I$(NODEMANAGER_INCLUDEDIR) \
-I$(JSONBOX_INCLUDEDIR) \
-I$(SQLITE_INCLUDEDIR)
COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
GSM_LA = $(top_builddir)/GSM/libGSM.la
SMS_LA = $(top_builddir)/SMS/libSMS.la
GLOBALS_LA = $(top_builddir)/Globals/libglobals.la
SR_LA = $(top_builddir)/SR/libSR.la
NODEMANAGER_LA = $(top_builddir)/NodeManager/libnodemanager.la -lzmq
SQLITE_LA = $(top_builddir)/sqlite3/libsqlite.la -ldl
MOSTLYCLEANFILES = *~

1
NodeManager Submodule

@ -0,0 +1 @@
Subproject commit c154368a55d081d7be241a14825e9a009dee093a

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2008, 2009, 2010, 2014 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@ -589,7 +589,7 @@ void TLUserData::parse(const TLFrame& src, size_t& rp)
mLength = src.readField(rp,8);
#if 1
// This tail() works because UD is always the last field in the PDU.
mRawData.clone(src.tail(rp));
mRawData.clone(src.alias().tail(rp));
// Should we do this here?
mRawData.LSB8MSB();
#else

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2008, 2014 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@ -734,7 +734,7 @@ class CPUserData : public GSM::L3ProtocolElement {
CPUserData(const RPMessage& RPM)
:L3ProtocolElement(),
mRPDU(RPM.bitsNeeded())
mRPDU(BitVector(RPM.bitsNeeded()))
{
RPM.write(mRPDU);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2008, 2014 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2008, 2014 Free Software Foundation, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.

2
SR

@ -1 +1 @@
Subproject commit 226fc1c28a82307f7fc0e3f99f47a025be7cae4c
Subproject commit 25e81ce18e371cc7e8641dd4bab90a7ff4973484

View File

@ -18,7 +18,7 @@ dnl You should have received a copy of the GNU General Public License
dnl along with this program. If not, see <http://www.gnu.org/licenses/>.
dnl
AC_INIT(smqueue,TRUNK)
AC_INIT(smqueue,4.0TRUNK)
AC_PREREQ(2.57)
AC_CONFIG_SRCDIR([config/Makefile.am])
AC_CONFIG_AUX_DIR([.])
@ -54,6 +54,20 @@ AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_C_BIGENDIAN
dnl Check for libzmq
if test ! -r "/usr/include/zmq.h" -a ! -r "/usr/local/include/zmq.h"; then
AC_MSG_ERROR([/usr/local/include/zmq.h not found. Install the range-libzmq package or manually build and install with $ sudo ./NodeManager/install_libzmq.sh])
fi
if test ! -r "/usr/include/zmq.hpp" -a ! -r "/usr/local/include/zmq.hpp"; then
AC_MSG_ERROR([/usr/local/include/zmq.hpp not found. Install the range-libzmq package or manually build and install with $ sudo ./NodeManager/install_libzmq.sh])
fi
AC_CHECK_LIB(zmq, zmq_init, ,[AC_MSG_ERROR([Cannot link with -lzmq. Install the range-libzmq package or manually build and install with $ sudo ./NodeManager/install_libzmq.sh])])
AC_MSG_CHECKING([whether libzmq installation works])
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <zmq.h>],
[zmq_init(1);])
],
[AC_MSG_RESULT([yes])],
[AC_MSG_ERROR([no. Install the range-libzmq package or manually build and install with $ sudo ./NodeManager/install_libzmq.sh])])
# Defines OSIP_CFLAGS, OSIP_INCLUDEDIR, and OSIP_LIBS
PKG_CHECK_MODULES(OSIP, libosip2)
@ -72,7 +86,7 @@ AC_CONFIG_FILES([\
Globals/Makefile \
GSM/Makefile \
SMS/Makefile \
SR/Makefile \
NodeManager/Makefile \
sqlite3/Makefile \
smqueue/Makefile \
testing/Makefile \

10
debian/changelog vendored
View File

@ -1,11 +1,5 @@
smqueue-public (3.2) UNRELEASED; urgency=low
* Public release
-- Kurtis <kheimerl@rangenetworks.com> Thu, 01 Aug 2013 16:13:52 -0700
smqueue-public (3.2) UNRELEASED; urgency=low
smqueue (4.0) untested; urgency=low
* Test
-- Donald C. Kirker <donald.kirker@rangenetworks.com> Mon, 22 Apr 2013 00:11:00 -0700
-- Donald C. Kirker <donald.kirker@rangenetworks.com> Mon, 22 Apr 2013 00:11:00 -0700

1
debian/compat vendored
View File

@ -1 +0,0 @@
1

15
debian/control vendored
View File

@ -1,19 +1,16 @@
Source: smqueue-public
Provides: smqueue
Source: smqueue
Section: comm
Priority: optional
Maintainer: Range Networks, Inc. <info@rangenetworks.com>
Homepage: http://www.rangenetworks.com/
Build-Depends: build-essential, debhelper (>= 7), libosip2-dev, pkg-config, autoconf
Build-Depends: build-essential, debhelper (>= 7), libosip2-dev, pkg-config, autoconf, libtool
Standards-Version: 3.7.3
Package: smqueue-public
Provides: smqueue
Version: TRUNK
Package: smqueue
Section: comm
Priority: optional
Architecture: any
Architecture: i386
Essential: no
Depends: sqlite, sqlite3 (>= 3.7), libosip2-4, libglib2.0-0, libgl1-mesa-glx, libc6, libasound2, pkg-config, libpcre3, gawk, screen
Description: OpenBTS Public software.
Depends: sqlite3, libosip2-4, libc6-i686, pkg-config, range-libzmq
Description: Range Networks - SMQueue RFC-3428 Store and Forward Server

16
debian/postinst vendored
View File

@ -19,15 +19,19 @@ set -e
configure()
{
DB_LOC=/etc/OpenBTS/smqueue.db
DATE=$(date +'%Y-%m-%d.%H:%M:%S')
CONFIG_BACKUP=$DB_LOC.dump-$DATE
DATE=$(date --rfc-3339='date')
CONFIG_BACKUP=/etc/OpenBTS/smqueue.dump-$DATE
if [ ! -e $DB_LOC ]; then
sqlite3 $DB_LOC ".dump" > $CONFIG_BACKUP
if [ ! -e $CONFIG_BACKUP ]; then
sqlite3 /etc/OpenBTS/smqueue.db ".dump" > $CONFIG_BACKUP
fi
sqlite3 $DB_LOC ".read /etc/OpenBTS/smqueue.example.sql" &>/dev/null
sqlite3 /etc/OpenBTS/smqueue.db ".read /etc/OpenBTS/smqueue.example.sql" &>/dev/null
if [ ! -e /var/lib/OpenBTS ]; then
mkdir /var/lib/OpenBTS
fi
}

18
debian/prerm vendored
View File

@ -16,20 +16,14 @@ set -e
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
APP=smqueue
remove()
{
if [ "$(pidof $APP)" ]; then
killall $APP
else
echo "$APP not running"
fi
}
# remove()
# {
# killall runloop.smqueue.sh &>/dev/null
# }
case "$1" in
remove|upgrade|deconfigure)
remove
# remove
;;
failed-upgrade)
@ -44,6 +38,6 @@ esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

2
debian/rules vendored
View File

@ -108,7 +108,7 @@ binary-common:
# dh_perl
dh_makeshlibs
dh_installdeb
dh_shlibdeps
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
dh_gencontrol
dh_md5sums
dh_builddeb

74
depcomp
View File

@ -1,10 +1,10 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2009-04-28.21; # UTC
scriptversion=2011-12-04.11; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
# Software Foundation, Inc.
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
# 2011 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -44,7 +44,7 @@ Environment variables:
object Object file output by `PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputing dependencies.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
@ -90,10 +90,18 @@ if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u="sed s,\\\\\\\\,/,g"
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
@ -158,10 +166,12 @@ gcc)
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
## that the space means something, we add a space to the output as
## well.
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
@ -405,6 +415,52 @@ tru64)
rm -f "$tmpdepfile"
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test "$stat" = 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/ \1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/ /
G
p
}' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
@ -503,7 +559,9 @@ makedepend)
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation

View File

@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2009-04-28.21; # UTC
scriptversion=2011-01-19.21; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@ -156,6 +156,10 @@ while test $# -ne 0; do
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
@ -186,6 +190,10 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
fi
shift # arg
dst_arg=$arg
# Protect names problematic for `test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
@ -200,7 +208,11 @@ if test $# -eq 0; then
fi
if test -z "$dir_arg"; then
trap '(exit $?); exit' 1 2 13 15
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
@ -228,9 +240,9 @@ fi
for src
do
# Protect names starting with `-'.
# Protect names problematic for `test' and other utilities.
case $src in
-*) src=./$src;;
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
@ -252,12 +264,7 @@ do
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
@ -385,7 +392,7 @@ do
case $dstdir in
/*) prefix='/';;
-*) prefix='./';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
@ -403,7 +410,7 @@ do
for d
do
test -z "$d" && continue
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then

53
missing
View File

@ -1,10 +1,10 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2009-04-28.21; # UTC
scriptversion=2012-01-06.13; # UTC
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
# 2008, 2009 Free Software Foundation, Inc.
# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
@ -84,7 +84,6 @@ Supported PROGRAM values:
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
@ -122,15 +121,6 @@ case $1 in
# Not GNU programs, they don't have --version.
;;
tar*)
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
exit 1
fi
;;
*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
@ -226,7 +216,7 @@ WARNING: \`$1' $msg. You should only need it if
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if test $# -ne 1; then
eval LASTARG="\${$#}"
eval LASTARG=\${$#}
case $LASTARG in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
@ -256,7 +246,7 @@ WARNING: \`$1' is $msg. You should only need it if
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if test $# -ne 1; then
eval LASTARG="\${$#}"
eval LASTARG=\${$#}
case $LASTARG in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
@ -318,41 +308,6 @@ WARNING: \`$1' is $msg. You should only need it if
touch $file
;;
tar*)
shift
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar "$@" && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar "$@" && exit 0
fi
firstarg="$1"
if shift; then
case $firstarg in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" "$@" && exit 0
;;
esac
case $firstarg in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" "$@" && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.

View File

@ -23,11 +23,11 @@ include $(top_srcdir)/Makefile.common
DESTDIR :=
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
AM_CXXFLAGS = -O3 -g -lpthread
AM_CXXFLAGS = -lrt -O3 -g -lpthread
EXTRA_DIST = \
README.smqueue \
smqueue.config.example
smqueue.conf
noinst_PROGRAMS = \
smqueue
@ -36,16 +36,27 @@ noinst_HEADERS = \
poll.h \
smnet.h \
smqueue.h \
smsc.h \
diskbackup.h
QueuedMsgHdrs.h \
SmqGlobals.h \
SmqMessageHandler.h \
SmqReader.h \
SmqWriter.h \
SmqTest.h
smsc.h
smqueue_SOURCES = \
poll.c \
smcommands.cpp \
smnet.cpp \
smqueue.cpp \
QueuedMsgHdrs.cpp \
SmqGlobals.cpp \
SmqMessageHandler.cpp \
SmqReader.cpp \
SmqWriter.cpp \
SmqTest.cpp \
smsc.cpp \
diskbackup.cpp
../SR/SubscriberRegistry.cpp
smqueue_LDADD = \
$(GLOBALS_LA) \
@ -53,14 +64,15 @@ smqueue_LDADD = \
$(GSM_LA) \
$(COMMON_LA) \
$(SQLITE_LA) \
$(SR_LA) \
$(SIP_LA) \
$(NODEMANAGER_LA) \
$(OSIP_LIBS)
install: smqueue
mkdir -p "$(DESTDIR)/OpenBTS/"
install smqueue "$(DESTDIR)/OpenBTS/"
install runloop.smqueue.sh "$(DESTDIR)/OpenBTS/"
mkdir -p "$(DESTDIR)/etc/init/"
install smqueue.conf "$(DESTDIR)/etc/init/"
mkdir -p "$(DESTDIR)/etc/OpenBTS/"
install smqueue.example.sql "$(DESTDIR)/etc/OpenBTS/"

64
smqueue/QueuedMsgHdrs.cpp Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* HeaderforMsgs.cpp
*
* Created on: Nov 27, 2013
* Author: scott
*/
#include "smqueue.h"
#include "QueuedMsgHdrs.h"
void * QueuedMsgHdrs::getpData()
{
return pData;
}
void QueuedMsgHdrs::setpData(void * data)
{
pData = data;
}
QueuedMsgHdrs::MessageType QueuedMsgHdrs::getMsgType() const
{
return msgType;
}
void QueuedMsgHdrs::setMsgType(MessageType msgType)
{
this->msgType = msgType;
}
SMqueue::short_msg_pending* QueuedMsgHdrs::getSmp() const
{
return smp;
}
void QueuedMsgHdrs::setSmp(SMqueue::short_msg_pending* smp)
{
this->smp = smp;
}

204
smqueue/QueuedMsgHdrs.h Normal file
View File

@ -0,0 +1,204 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* QueuedMsgHdrs.h
*
* Created on: Nov 27, 2013setbufferSize
* Author: scott
* Header for message being sent in SMQ
*/
#ifndef HEADERFORMSGS_H_
#define HEADERFORMSGS_H_
class QueuedMsgHdrs {
public:
enum MessageType {
TestMessage = 1,
SIPAckMsg = 2,
SendResponse = 3,
ProcessIncommingMsg = 4
};
QueuedMsgHdrs() {}
QueuedMsgHdrs(enum MessageType eMessageType, void * ptr, int MessageSize) {
this->msgType = eMessageType;
pData = ptr;
smp = 0;
setMessageSize(sizeof(QueuedMsgHdrs));
}
virtual ~QueuedMsgHdrs() {
//LOG(DEBUG) << "QueuedMsgHdrs DTOR";
}
void setpData(void * data);
void * getpData();
void setMsgType(enum MessageType msgType);
MessageType getMsgType() const;
SMqueue::short_msg_pending* getSmp() const;
void setSmp(SMqueue::short_msg_pending* smp);
int getMessageSize() { return messageSize; }
void setMessageSize(int iSize) { messageSize = iSize; }
virtual int ProcessMessage() {
// Not currently used
LOG(DEBUG) << "Process message QueuedMsgHdrs DID NOTHING";
}
private:
MessageType msgType;
SMqueue::short_msg_pending *smp; // the message in the queue
void * pData;
int messageSize;
};
class SIPAckMessage : public QueuedMsgHdrs {
public:
SIPAckMessage(int err, SMqueue::short_msg_pending * smp, char * netaddr, size_t netaddrlen) {
setMsgType(QueuedMsgHdrs::SIPAckMsg);
setSmp(smp); // Use the pointer later
setpData(0);
this->errcode = err;
this->netaddr = netaddr;
this->netaddrlen = netaddrlen;
setMessageSize(sizeof(SIPAckMessage));
}
virtual ~SIPAckMessage() {
// QueuedMsgHdrs dtor will delete smp
//LOG(DEBUG) << "SIPAckMessage DTOR";
}
int getErrcode() const
{
return errcode;
}
void setErrcode(int errcode)
{
this->errcode = errcode;
}
char* getNetaddr() const
{
return netaddr;
}
void setNetaddr(char* netaddr)
{
this->netaddr = netaddr;
}
size_t getNetaddrlen() const
{
return netaddrlen;
}
void setNetaddrlen(size_t netaddrlen)
{
this->netaddrlen = netaddrlen;
}
virtual int ProcessMessage() {
LOG(DEBUG) << "Process message SIPAckMessage";
smq.respond_sip_ack(this->getErrcode(), (SMqueue::short_msg_pending *) this->getSmp(), // Real call to respond_sip_ack on writer thread
(char *) this->getNetaddr(), (int) this->getNetaddrlen());
return 0;
}
private:
int errcode;
char* netaddr;
size_t netaddrlen;
};
class TestMessage : public QueuedMsgHdrs {
public:
TestMessage(std::string sMsg) {
strcpy(msg, sMsg.c_str());
setMsgType(QueuedMsgHdrs::TestMessage);
setSmp(0);
setpData(0);
setMessageSize(sizeof(TestMessage));
}
virtual ~TestMessage() {
//LOG(DEBUG) << "TestMessage DTOR";
}
virtual int ProcessMessage() {
LOG(DEBUG) << "Process message TestMessage msg:" << msg; // Log is all this message has to do currently
}//
private:
char msg[50];
};
class ProcessIncommingMsg : public QueuedMsgHdrs {
public:
// Message will be sent to the writer thread so that msgs will be processed
ProcessIncommingMsg() {
setMsgType(QueuedMsgHdrs::ProcessIncommingMsg);
setSmp(0);
setpData(0);
setMessageSize(sizeof(ProcessIncommingMsg));
}
virtual ~ProcessIncommingMsg() {
//LOG(DEBUG) << "ProcessIncommingMsg DTOR";
}
virtual int ProcessMessage() {
// Got a message in the queue go handle it
LOG(DEBUG) << "Process message ProcessIncommingMsg";
smq.process_timeout();
}
};
class SimpleWrapper {
public:
SimpleWrapper(QueuedMsgHdrs* pData) {
msgPtr = pData;
}
~SimpleWrapper() {
// don't delete msgPtr this will be doe by receiving client
//LOG(DEBUG) << "SimpleWrapper DTOR";
}
int getSize() { return sizeof(SimpleWrapper); }
QueuedMsgHdrs* getMsgPtr() { return msgPtr; }
void setMsgPtr(QueuedMsgHdrs* pData) { msgPtr = pData; }
private:
QueuedMsgHdrs* msgPtr;
}; // SimpleWrapper
#endif /* HEADERFORMSGS_H_ */

97
smqueue/SmqGlobals.cpp Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqGlobals.cpp
*
* Created on: Nov 21, 2013
* Author: scott
* Some common resource used by SMQ
*/
#include "SmqGlobals.h"
#include <Logger.h>
SmqGlobals::SmqGlobals() {
}
SmqGlobals::~SmqGlobals() {
}
unsigned long getCurrentSeconds() {
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);;
unsigned long time_in_sec =
tv.tv_sec + (tv.tv_nsec / 1000000000UL) ; // convert tv_sec & tv_usec to millisecond
return time_in_sec;
}
/*
* Returns current MS
*/
unsigned long getCurrentMS() {
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
unsigned long time_in_mill =
(tv.tv_sec * 1000UL) + (tv.tv_nsec / 1000000UL) ; // convert tv_sec & tv_usec to millisecond
return time_in_mill;
}
/*
* Returns MS from timespec
*/
unsigned long getMSFromtimespec(struct timespec tv) {
unsigned long time_in_mill =
(tv.tv_sec * 1000UL) + (tv.tv_nsec / 1000000UL) ; // convert tv_sec & tv_usec to millisecond
return time_in_mill;
}
struct timespec addTimespec(struct timespec tv1, struct timespec tv2) {
struct timespec tvret;
tvret.tv_sec = tv1.tv_sec + tv2.tv_sec;
tvret.tv_nsec = tv1.tv_nsec + tv2.tv_nsec;
if (tvret.tv_nsec >= NS_IN_SEC) {
tvret.tv_sec++;
tvret.tv_nsec = tvret.tv_nsec - NS_IN_SEC;
}
return tvret;
}
void msSleep(int ms) {
usleep(ms*1000); // Convert to microseconds
return;
}
time_t msgettime() {
//LOG(DEBUG) << "Enter msgettime";
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
unsigned long time_in_mill =
(tv.tv_sec * 1000UL) + (tv.tv_nsec / 1000000UL) ; // convert tv_sec & tv_usec to millisecond
//LOG(DEBUG) << "Return msgettime ms" << time_in_mill;
return time_in_mill;
}

52
smqueue/SmqGlobals.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqGlobals.h
*
* Created on: Nov 21, 2013
* Author:
*/
#ifndef SMQGLOBALS_H_
#define SMQGLOBALS_H_
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#define CLOCK_REALTIME 0 // Fix this svgfix
#define NS_IN_SEC 1000000000L // Number of nano seconds in a second
//#define mq_printf(str, arg...) printf("%d : "str, getpid(), ##arg) // Original
#define mq_printf(str, arg...) printf("ms:%lu tid:%lu: "str, getCurrentMS(), pthread_self(), ##arg)
class SmqGlobals {
public:
SmqGlobals();
virtual ~SmqGlobals();
};
extern unsigned long getCurrentMS();
extern unsigned long getMSFromtimespec(struct timespec tv);
extern struct timespec addTimespec(struct timespec tv1, struct timespec tv2);
extern void msSleep(int ms);
extern time_t msgettime();
extern unsigned long getCurrentSeconds();
#endif /* SMQGLOBALS_H_ */

View File

@ -0,0 +1,275 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqMessageHandler.cpp
*
* Created on: Nov 16, 2013
* Author:
*
*
*/
#include "smqueue.h"
#include "QueuedMsgHdrs.h"
#include "SmqMessageHandler.h"
#include "SmqReader.h"
#include "SmqWriter.h"
// Pointers to handlers for the reader and writer queues
SmqReader* smqReader;
SmqWriter* smqWriter;
// Static function to start the threads
void SmqMessageHandler::StartThreads() {
LOG(INFO) << "Start reader and writer threads";
smqReader = new SmqReader();
smqWriter = new SmqWriter();
}
SmqMessageHandler::~SmqMessageHandler() {
/* Close the message queue */
int ret = mq_close(mqdes);
if (ret)
LOG(DEBUG) << "Message queue close failed";
else
LOG(DEBUG) << "Message queue closed";
}
/*
returns
0 = sent okay
-1 failed
Should only be used for test need header for all msgs
Delete after clean up
*/
int SmqMessageHandler::SmqSendMessage(SimpleWrapper * pMsg) {
int returnValue;
int ret;
//LOG(DEBUG) << "Sending message to queue:" << getQueueName();;
// Wait for queue to open
while (!queueOpened()) {
LOG(DEBUG) << "Try to open queue:" << getQueueName() << "in SmqSendMessage";
mqueueOpened = SmqInitReceiver(); // Set up the queue name
if (queueOpened()) {
LOG(DEBUG) << "Successfully opened queue for sender queue:" << getQueueName();
//break;
}
msSleep(2000);
} // while
ret = mq_send(mqdes, (char*) pMsg, pMsg->getSize(), 0);
if (ret) {
LOG(DEBUG) << "Message failed to be sent error:" << ret << " errno:" << errno;
returnValue = -1;
}
else {
//LOG(DEBUG) << "Message sent okay queue:" << getQueueName();
returnValue = 0;
}
return returnValue;
}
int SmqMessageHandler::SmqDeleteMessage() {
return 0;
}
std::string SmqMessageHandler::getQueueName() {
return mqueueName;
}
bool SmqMessageHandler::queueOpened() {
return mqueueOpened;
}
/*
* Return
* Message okay = size of message
* -x = Failed
* 0 = Timeout
*
*/
int SmqMessageHandler::SmqWaitforMessage(int TimeoutMS, char * MsgBuffer, int MsgBufferSize) {
int msgLength = 0;
struct mq_attr attrList;
//LOG(DEBUG) << "Waiting for message in queue:" << getQueueName() << " tmo:" << TimeoutMS << " bufsize:" << MsgBufferSize;
// Wait for queue to open. This may not be needed
while (!queueOpened()) {
LOG(DEBUG) << "Try to open queue:" << getQueueName() << " in SmqWaitforMessage";
mqueueOpened = SmqInitReceiver(); // Set up the queue name
if (mqueueOpened) {
LOG(DEBUG) << "Successfully opened queue:" << getQueueName() << " in SmqWaitforMessage";
break;
}
msSleep(2000);
} // while
//mq_getattr(mqdes, &attrList);
//LOG(DEBUG) << "mq_attr flags:%ld maxmsg:%ld mq_msgsize:%ld mq_curmsg:%ld",
//attrList.mq_flags, attrList.mq_maxmsg, attrList.mq_msgsize, attrList.mq_curmsgs);
/* get the current time at which mq_receive() is going to be called
i.e time since the Epoch time, 1970-01-01 00:00:00 +0000 (UTC) */
clock_gettime(CLOCK_REALTIME, &currenttime_before);
struct timespec wait_timeout; // Put delay in time spec
wait_timeout.tv_sec = (TimeoutMS / 1000);
wait_timeout.tv_nsec = ((TimeoutMS % 1000) * 1000000);
abs_timeout = addTimespec(currenttime_before, wait_timeout);
// Wait for the message
// LOG(DEBUG) << "Real enter wait for message in queue:"<< getQueueName().c_str() << " tmo:" << TimeoutMS;
msgLength = mq_timedreceive(mqdes, MsgBuffer, MsgBufferSize, &msg_prio, &abs_timeout);
#if 0
// only enable for debugging
clock_gettime(CLOCK_REALTIME, &currenttime_after);
/* Get the time at which the message queue returns */
LOG(DEBUG) << "Message queue:%s size:%ld", mqueueName.c_str(), getMessageQueueSize());
/* Print all time values. We didn't print anything before to avoid the delay caused by printf() */
LOG(DEBUG) << "Time before mq_timedreceive is called sec:%ld ns:%ld ms:%lu",
currenttime_before.tv_sec, currenttime_before.tv_nsec, getMSFromtimespec(currenttime_before));
LOG(DEBUG) << "Absolute time passed to mq_timedreceive sec:%ld ns:%ld ms:%lu",
abs_timeout.tv_sec, abs_timeout.tv_nsec, getMSFromtimespec(abs_timeout));
LOG(DEBUG) << "Time at which mq_timedreceive returned sec:%ld ns:%ld ms:%lu",
currenttime_after.tv_sec, currenttime_after.tv_nsec, getMSFromtimespec(currenttime_after));
LOG(DEBUG) << "Actual wait time ms:%ld",
getMSFromtimespec(currenttime_after) - getMSFromtimespec(currenttime_before));
//LOG(DEBUG) << "Actual passed to wait ms:%lu", getMSFromtimespec(abs_timeout));
#endif
if (msgLength < 0)
{ /* mq_timedreceive returned with an error */
//LOG(DEBUG) << "Wait for message receive got errno:%d error:%d", errno, msgLength);
if (errno == ETIMEDOUT) { // errno = 110
// ********* TIMEOUT ***************************
//LOG(DEBUG) << "Wait for message got timeout");
msgLength = 0;
} else {
// *********** GOT ERROR ******************
//Check for other errors like signal to stop EINTR
LOG(DEBUG) << "Wait for message receive got errno:" << errno << " error:" << msgLength;
// Return current value of msgLength
}
}
else {
/* *****************GOT MESSAGE **************** */
//LOG(DEBUG) << "Successfully received %d bytes", (int) msgLength);
}
return msgLength;
}
/*
Returns
true = okay
*/
bool SmqMessageHandler::SmqInitReceiver() {
bool retValue = false;
LOG(DEBUG) << "SmqInitReceiver queue name:" << mqueueName;
/* Create message queue */
mqdes = mq_open(mqueueName.c_str(), O_RDWR | O_CREAT, MQ_MODE, &attr); // Should be this one
if (mqdes != (mqd_t)-1 ) {
LOG(DEBUG) << "Message queue opened:" << mqueueName;
retValue = true;
mqueueOpened = true;
}
else {
LOG(DEBUG) << "Message Queue FAILED to open";
LOG(DEBUG) << "mq_open error:" << errno << " mqdes:" << mqdes;
retValue = false;
}
return retValue;
}
long SmqMessageHandler::getMessageQueueSize() {
int error;
long count = -1;
struct mq_attr localAttr;
error = mq_getattr(mqdes, &localAttr);
if (!error)
count = localAttr.mq_curmsgs;
return count;
}
/*
* Send a QueuedMsgHdrs to writer queue
* Deleted SimpleWrapper receiver deletes attached message
*/
int SendWriterMsg(SimpleWrapper* pMsg) {
int iret;
iret = smqWriter->getqueHan()->SmqSendMessage(pMsg);
delete pMsg; // Delete SimpleWrapper
return iret;
}
/*
Send a message to the writer thread asking for a sip ack to be sent
*/
void queue_respond_sip_ack(int errcode, SMqueue::short_msg_pending *shortmsg, char * netaddr, size_t netaddrlen) {
LOG(DEBUG) << "Send SIP ACK queue request";
QueuedMsgHdrs* pMsg = new SIPAckMessage(errcode, shortmsg, netaddr, netaddrlen);
SimpleWrapper* sWrap = new SimpleWrapper(pMsg);
SendWriterMsg(sWrap); // Message gets deleted in here
}
// Signal writer thread to process incoming message
void ProcessReceivedMsg() {
LOG(DEBUG) << "Signal writer thread ProcessReceivedMsg";
QueuedMsgHdrs* pMsg = new ProcessIncommingMsg();
SimpleWrapper* sWrap = new SimpleWrapper(pMsg);
SendWriterMsg(sWrap);
}
// Only used for testing
void SendTestMessage() {
QueuedMsgHdrs* pMsg = new TestMessage("Test message from reader thread");
SimpleWrapper* sWrap = new SimpleWrapper(pMsg);
SendWriterMsg(sWrap); // Message gets deleted in here
}

107
smqueue/SmqMessageHandler.h Normal file
View File

@ -0,0 +1,107 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqMessageHandler.h
*
* Created on: Nov 16, 2013
using namespace std;
using namespace SMqueue;
extern ConfigurationTable gConfig;
* Author: Scott
* This code implements the wait for event function
*/
#ifndef SMQMESSAGEHANDLER_H_
#define SMQMESSAGEHANDLER_H_
#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <time.h>
#include <errno.h>
#include <string>
#include "SmqGlobals.h"
#include <unistd.h>
void queue_respond_sip_ack(int errcode, SMqueue::short_msg_pending *shortmsg, char * netaddr, size_t netaddrlen);
void ProcessReceivedMsg();
void SendTestMessage();
using namespace std;
/*
These are the upper limit on queue sizes
/proc/sys/fs/mqueue/msg_max: 1100
/proc/sys/fs/mqueue/msgsize_max: 1000
/proc/sys/fs/mqueue/queues_max: 256
*/
#define MQ_MESSAGE_MAX_SIZE 1100
#define MQ_MAX_NUM_OF_MESSAGES 100
#define MQ_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/*
errno
13 permission denied
14
22 EINVAL
90 EMSGSIZE Message too long (POSIX.1)
110 ETIMEDOUT
*/
class SmqMessageHandler {
public:
static void StartThreads();
SmqMessageHandler(string queueName) {
/* Form the queue attributes */
attr.mq_flags = 0; /* i.e mq_send will be block if message queue is full */
attr.mq_maxmsg = MQ_MAX_NUM_OF_MESSAGES;
attr.mq_msgsize = MQ_MESSAGE_MAX_SIZE;
attr.mq_curmsgs = 0;
msg_prio = 0;
mqueueName = queueName;
mqueueOpened = false;
}
~SmqMessageHandler();
int SmqDeleteMessage();
int SmqWaitforMessage(int TimeoutMS, char * MsgBuffer, int MsgBufferSize);
bool SmqInitReceiver();
string getQueueName();
bool queueOpened();
long getMessageQueueSize();
// Send functions
int SmqSendMessage(SimpleWrapper * pMsg);
private:
// Message queue
mqd_t mqdes; // Message queue
struct mq_attr attr;
unsigned msg_prio;
struct timespec currenttime_before;
struct timespec abs_timeout;
struct timespec currenttime_after;
string mqueueName; // Name used with this message queue
bool mqueueOpened;
};
#endif /* SMQMESSAGEHANDLER_H_ */

108
smqueue/SmqReader.cpp Normal file
View File

@ -0,0 +1,108 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqReader.cpp
*
* Created on: Nov 16, 2013
* Author: Scott Van Gundy
*/
#include <string>
#include "smqueue.h"
#include "QueuedMsgHdrs.h"
#include "SmqMessageHandler.h"
#include "SmqReader.h"
#include <Logger.h>
std::string SmqReader::MQ_NAME = "/SmqReader";
extern SmqReader* smqReader;
SmqReader::~SmqReader() {
delete mqueHan;
}
void* SmqReader::SmqReaderThread(void* ptr) {
LOG(DEBUG) <<"Start SMQ reader thread";
char msgBuffer[MQ_MESSAGE_MAX_SIZE+10]; // Must be larger than size speced in attr
int bytesRead = 0;
int msgCount = 0;
smq.InitBeforeMainLoop();
smq.InitInsideReaderLoop(); // Updates configuration do here to make sure everything is setup for threads
// Queue opened Process messages
LOG(DEBUG) << "Enter reader thread loop";
while (!smq.stop_main_loop) {
smq.main_loop(60000);
#if 0
// Put this back in if process messages in reader thread
LOG(DEBUG) <<"Start SMQ reader thread loop";
bytesRead = smqReader->getqueHan()->SmqWaitforMessage(2000, msgBuffer, sizeof(msgBuffer)); // Wait for message
//LOG(DEBUG) << "Got return from SmqWaitforMessage in reader thread status:%d", bytesRead);
if (bytesRead < 0) {
// GOT ERROR
LOG(DEBUG) << "Reader failed to get message:" << bytesRead;
} else if (bytesRead == 0) {
// TIMEOUT
LOG(DEBUG) << "Got timeout waiting for reader message";
//Add timeout stuff here
//LOG(DEBUG) << "Enter InitInsideReaderLoop";
smq.InitInsideReaderLoop(); // Updates configuration Moved this to writer queue
//LOG(DEBUG) << "Return from InitInsideReaderLoop";
// This is where all the work is done
// Message are read in here
//LOG(DEBUG) << "Enter main_loop";
smq.main_loop(2000);
//LOG(DEBUG) << "Return from main_loop";
} else if (bytesRead > 0) {
// GOT MESSAGE
LOG(DEBUG) << "Received message in reader thread length;" << bytesRead;
// PROCESS MESSAGES HERE
#if 0
switch (msgType) {
case QueuedMsgHdrs::TestMessage:
break;
case QueuedMsgHdrs::SendResponse: // this is a writer message
break;
} // switch
#endif
}
#endif
} // while
smq.CleaupAfterMainreaderLoop();
LOG(DEBUG) << "End SMQ reader thread";
return NULL;
}

54
smqueue/SmqReader.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqReader.h
*
* Created on: Nov 16, 2013
* Author: Scott
*/
#ifndef SMQREADER_H_
#define SMQREADER_H_
class SmqReader {
public:
static std::string MQ_NAME;
SmqReader() {
// create message handler
mqueHan = new SmqMessageHandler(SmqReader::MQ_NAME);
// Start reader thread
pthread_create(&mthread_ID, NULL, SmqReaderThread, (void*) NULL);
}
~SmqReader();
static void* SmqReaderThread(void * ptr);
// get handle to message queue
SmqMessageHandler * getqueHan() {
return mqueHan;
}
private:
pthread_t mthread_ID;
SmqMessageHandler* mqueHan;
bool please_re_exec;
};
#endif /* SMQREADER_H_ */

174
smqueue/SmqTest.cpp Normal file
View File

@ -0,0 +1,174 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqTest.cpp
*
* Created on: Dec 16, 2013
* Author: scott
*/
#include "SmqTest.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
using namespace std;
#include "smqueue.h"
#include "QueuedMsgHdrs.h"
#include "SmqMessageHandler.h"
#include "SmqReader.h"
#include "SmqWriter.h"
#include "SmqGlobals.h"
extern SmqReader* smqReader;
extern SmqWriter* smqWriter;
#define REPEAT 10000
pthread_t thread1, thread2;
void* ReaderTestThread(void *ptr) {
LOG(DEBUG) << "Starting reader test thread";
int msgCount = 0;
int repeatCount = 0;
//while (true) {
while (++repeatCount < REPEAT) {
//LOG(DEBUG) << "Send TestMessage from reader test thread");
SendTestMessage(); // Send message to writer thread
//LOG(DEBUG) << "Call originate_sm from readertestthread")
//smq.originate_sm("TEST1", "TEST2", "This is a test msg from reader test", SMqueue::INITIAL_STATE); // fake an incommming message
msSleep(1000);
}
LOG(DEBUG) << "Reader test thread stopped";
return NULL;
}
static int gLevel = 1;
void RecursiveMutextTest(int Level) {
int iLevel = Level;
if (Level > 3) return;
LOG(DEBUG) << "Enter Level " << iLevel;
smq.lockSortedList();
LOG(DEBUG) << "In lock level " << iLevel;
gLevel++;
RecursiveMutextTest(gLevel);
LOG(DEBUG) << "Back from recursive call " << iLevel;
smq.unlockSortedList();
LOG(DEBUG) << "Unlock from Level " << iLevel;
} // RecursiveMutextTest
// Send fake input to the input socket incomming default 5063
#define MAX 100
#define tport 5063
void WriteToUDP() {
int sfd, n;
char buffer[MAX];
struct sockaddr_in saddr;
char IPAddress[100];
socklen_t len;
int ret;
int portNum;
// Set up test
int repeat = 10;
strcpy(IPAddress, "127.0.0.1");
portNum = tport;
sfd = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
inet_pton(AF_INET, IPAddress, &saddr.sin_addr);
saddr.sin_port = htons(portNum);
LOG(DEBUG) << "WriteToUDP running " << repeat;
while(repeat-- > 0) {
for (int i = 0; i < sizeof(buffer); i++) { // Write a pattern to the buffer for each write.
buffer[i] = 0;
}
len=sizeof(saddr);
LOG(DEBUG) << "Write to UDP port";
ret = sendto(sfd, buffer, sizeof(buffer), 0, (struct sockaddr *) &saddr, len);
LOG(DEBUG) << "Send length " << ret << " of " << len;
msSleep(5000);
} // while
} // WriteToUDP
void* WriterTestThread(void *ptr) {
LOG(DEBUG) << "Starting writer test thread";
int msgCount = 0;
int repeatCount = 0;
// WriteToUDP(); // just run once
RecursiveMutextTest(gLevel);
//while (true) {
while (++repeatCount < REPEAT) {
// Send message to writer
//LOG(DEBUG) << "Send msg %d from Writer test thread repeat: %d", msgCount, repeatCount);
//msgCount++;
//char buffer[50];
//sprintf(buffer, "Writer test thread message:%d", msgCount);
msSleep(2000);
}
return NULL;
} // WriterTestThread
void StartTestThreads() {
LOG(DEBUG) << "Start test threads version 14";
#if 0
// msSleep(5000); //svgfix
//pthread_create(&thread1, NULL, ReaderTestThread, (void*) NULL);
pthread_create(&thread2, NULL, WriterTestThread, (void*) NULL);
#endif
}

38
smqueue/SmqTest.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqTest.h
*
* Created on: Dec 16, 2013
* Author: scott
*/
#ifndef SMQTEST_H_
#define SMQTEST_H_
void StartTestThreads();
#if 0
class SmqTest {
public:
SmqTest();
virtual ~SmqTest();
};
#endif
#endif /* SMQTEST_H_ */

112
smqueue/SmqWriter.cpp Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqWriter.cpp
*
* Created on: Nov 16, 2013
* Author: Scott Van Gundy
*/
#include <string>
#include "smqueue.h"
#include "QueuedMsgHdrs.h"
#include "SmqMessageHandler.h"
#include "SmqWriter.h"
#include <Logger.h>
extern SmqWriter* smqWriter;
extern SMqueue::SMq smq;
std::string SmqWriter::MQ_NAME = "/SmqWriter";
SmqWriter::~SmqWriter() {
delete mqueHan;
}
void* SmqWriter::SmqWriterThread(void * ptr) {
LOG(DEBUG) <<"Start SMQ writer thread";
char msgBuffer[MQ_MESSAGE_MAX_SIZE+10];
int bytesRead = 0;
int msgCount = 0;
SimpleWrapper* pWrap;
QueuedMsgHdrs* pMsg;
unsigned long currentSeconds;
unsigned long lastRunSeconds;
SMqueue::short_msg_pending pendingMsg;
// Queue opened Process messages
currentSeconds = getCurrentSeconds();
lastRunSeconds = currentSeconds;
LOG(DEBUG) << "Enter writer thread loop";
while (!smq.stop_main_loop) {
//LOG(DEBUG) <<"Start SMQ writer thread loop";
bytesRead = smqWriter->getqueHan()->SmqWaitforMessage(200, msgBuffer, (int) sizeof(msgBuffer));
currentSeconds = getCurrentSeconds();
//LOG(DEBUG) << "Got return from SmqWaitforMessage in writer status:" << bytesRead;
if (bytesRead < 0) {
LOG(DEBUG) << "Writer failed to get message:" << bytesRead;
} else if (bytesRead == 0) {
// ******** Got timeout ***************
//LOG(DEBUG) << "Got timeout in writer thread";
smq.process_timeout(); // Process entries in queue
//LOG(DEBUG) << "Return from process_timeout";
if ((currentSeconds - lastRunSeconds ) > 60) {
LOG(DEBUG) << "Run once a minute stuff";
smq.InitInsideReaderLoop(); // Updates configuration
int queueSize = smq.time_sorted_list.size();
if (queueSize > 0) { LOG(DEBUG) << "Queue size " << queueSize;}
// Save queue to file on timeout
//LOG(DEBUG) << "Enter save_queue_to_file";
if (!smq.save_queue_to_file(smq.savefile)) { // Save queue file each timeout may want to slow this down
LOG(WARNING) << "Failed to read queue file on timeout file:" << smq.savefile;
}
lastRunSeconds = currentSeconds;
}
} else if (bytesRead > 0) {
// ********* Got message *************
//LOG(DEBUG) << "Received message in writer thread length:" << bytesRead;
pWrap = (SimpleWrapper*) msgBuffer;
pMsg = pWrap->getMsgPtr();
// PROCESS MESSAGES HERE
pMsg->ProcessMessage();
delete pMsg;
} // Got message
} // while
LOG(DEBUG) << "End SMQ writer thread";
return NULL;
}

49
smqueue/SmqWriter.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* SmqWriter.h
*
* Created on: Nov 16, 2013
* Author: Scott Van Gundy
*/
#ifndef SMQWRITER_H_
#define SMQWRITER_H_
class SmqWriter {
public:
static std::string MQ_NAME;
SmqWriter() {
mqueHan = new SmqMessageHandler(SmqWriter::MQ_NAME);
pthread_create(&mthread_ID, NULL, SmqWriterThread, (void*) NULL);
}
~SmqWriter();
static void* SmqWriterThread(void * ptr);
SmqMessageHandler* getqueHan() {
return mqueHan;
}
private:
pthread_t mthread_ID;
SmqMessageHandler* mqueHan;
};
#endif /* SMQWRITER_H_ */

View File

@ -1,155 +0,0 @@
/*
* Copyright 2012 Range Networks, Inc.
*
* Written by Kurtis Heimerl, November 2012
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "diskbackup.h"
#include <sys/stat.h>
#include "sqlite3.h"
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <Configuration.h>
extern ConfigurationTable gConfig;
using namespace std;
#define MICROSECONDS 1000000L
//basically a copy of the datastructure but in a table
static const char* createMessageTable = {
"CREATE TABLE IF NOT EXISTS MESSAGES ("
"timestamp integer UNIQUE not null, "
"message text not null"
")"
};
//kurtis utility function
long long get_msecs(){
struct timeval tv;
gettimeofday(&tv, NULL);
long long seconds = tv.tv_sec;
seconds *= MICROSECONDS;
seconds += tv.tv_usec;
return seconds;
}
int SQLiteBackup::init()
{
string ldb = gConfig.getStr("Backup.db");
size_t p = ldb.find_last_of('/');
if (p == string::npos) {
LOG(EMERG) << "Backup.db not in a directory?";
mDB = NULL;
return FAILURE;
}
string dir = ldb.substr(0, p);
struct stat buf;
if (stat(dir.c_str(), &buf)) {
LOG(EMERG) << dir << " does not exist";
mDB = NULL;
return FAILURE;
}
int rc = sqlite3_open(ldb.c_str(),&mDB);
if (rc) {
LOG(EMERG) << "Cannot open SQLiteBackup database: " << sqlite3_errmsg(mDB);
sqlite3_close(mDB);
mDB = NULL;
return FAILURE;
}
if (!sqlite3_command(mDB,createMessageTable)) {
LOG(EMERG) << "Cannot create MESSAGES table";
return FAILURE;
}
return SUCCESS;
}
SQLiteBackup::~SQLiteBackup()
{
if (mDB) sqlite3_close(mDB);
}
backup_msg_list* SQLiteBackup::get_stored_messages(){
//record stale messages
//should be config variable at some point -kurtis
long long min_time = get_msecs() - (72 * 60 * 60 * MICROSECONDS); //hrs*minutes*seconds*microseconds
char cmd[100];
sprintf(cmd,"SELECT * FROM MESSAGES WHERE timestamp < %lld", min_time);
sqlite3_stmt *stmt;
if (sqlite3_prepare_statement(mDB,&stmt,cmd)) return NULL;
int src = sqlite3_run_query(mDB,stmt);
int i = 0;
while (src==SQLITE_ROW) {
i++;
src = sqlite3_run_query(mDB,stmt);
}
LOG(NOTICE) << "REMOVING " << i << " STALE MESSAGES";
//remove stale messages
sprintf(cmd,"DELETE FROM MESSAGES WHERE timestamp < %lld", min_time);
if (sqlite3_prepare_statement(mDB,&stmt,cmd)) return NULL;
src = sqlite3_run_query(mDB,stmt);
//get the remaining messages
sprintf(cmd,"SELECT timestamp,message FROM MESSAGES");
if (sqlite3_prepare_statement(mDB,&stmt,cmd)) return NULL;
// Read the result.
backup_msg_list* list = new backup_msg_list(0);
src = sqlite3_run_query(mDB,stmt);
while (src==SQLITE_ROW) {
long long timestamp = sqlite3_column_int64(stmt,0);
string text = (char *)sqlite3_column_text(stmt,1);
backup_msg msg;
msg.timestamp = timestamp;
msg.text = text;
list->push_back(msg);
src = sqlite3_run_query(mDB,stmt);
}
sqlite3_finalize(stmt);
return list;
}
int SQLiteBackup::insert(long long timestamp, char* text)
{
ostringstream os;
os << "INSERT into MESSAGES (timestamp, message) values (";
os << "\"" << timestamp << "\"";
os << ",";
os << "\"" << text << "\"";
os << ")";
LOG(INFO) << "Inserting " << timestamp << " into backup db";
LOG(DEBUG) << "Inserting " << timestamp << ":" << text;
return sqlite3_command(db(), os.str().c_str());
}
int SQLiteBackup::remove(long long timestamp)
{
ostringstream os;
os << "DELETE from MESSAGES WHERE timestamp=";
os << timestamp;
LOG(INFO) << "Trying to remove " << timestamp << " from backup db";
return sqlite3_command(db(), os.str().c_str());
}

View File

@ -1,92 +0,0 @@
/*
* Copyright 2012 Range Networks, Inc.
*
* Written by Kurtis Heimerl, November 2012
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* This class stores messages for later replay if SMQ fails */
#ifndef DISK_BACKUP_H
#define DISK_BACKUP_H
#include <Logger.h>
#include <sys/time.h>
#include <string.h>
#include "sqlite3util.h"
using namespace std;
typedef struct {
long long timestamp;
string text;
} backup_msg;
typedef std::list<backup_msg> backup_msg_list;
//kurtis utility function
long long get_msecs();
class SQLiteBackup {
private:
sqlite3 *mDB; ///< database connection
public:
~SQLiteBackup();
/**
Initialize the backup using parameters from gConfig.
@return 0 if the database was successfully opened and initialized; 1 otherwise
*/
int init();
typedef enum {
SUCCESS=0, ///< operation successful
FAILURE=1, ///< operation not successful
DELAYED=2, ///< operation successful, but effect delayed
TRYAGAIN=3 ///< operation not attempted, try again later
} Status;
sqlite3 *db()
{
return mDB;
}
/* get all the current elements in the db */
/* responsibility on caller to delete each entry as well as the list
-kurtis */
backup_msg_list* get_stored_messages();
/* insert a message into the storage */
int insert(long long timestamp, char* text);
/* remove an element from storage */
int remove(long long timestamp);
};
#endif //diskbackup.h

View File

@ -37,7 +37,7 @@
This software is released under the following license:
Copyright (c) 1995-2002 Brian M. Clapper
Copyright (c) 1995-2014 Brian M. Clapper
All rights reserved.
Redistribution and use in source and binary forms are

View File

@ -37,7 +37,7 @@
This software is released under the following license:
Copyright (c) 1995-2002 Brian M. Clapper
Copyright (c) 1995-2014 Brian M. Clapper
All rights reserved.
Redistribution and use in source and binary forms are

View File

@ -1,4 +0,0 @@
#!/bin/sh
# A script to restart and just keep smqueue running.
while true; do killall smqueue; sleep 2; ./smqueue; done

45
smqueue/setUpFiles.sh Normal file
View File

@ -0,0 +1,45 @@
#!/bin/sh
# Install smqueue and associated configuration files.
if [ $# -eq 1 ]; then
PREFIX=$1
else
if [ "$USER" != "root" ]; then
echo This script must be run as super-user.
exit 1
fi
PREFIX=""
fi
INSTALL_DIR=$PREFIX/OpenBTS
UPSTART_DIR=$PREFIX/etc/init
CONFIG_DIR=$PREFIX/etc/OpenBTS
if [ ! -e $INSTALL_DIR ]; then
mkdir -p $INSTALL_DIR
fi
if [ ! -e $UPSTART_DIR ]; then
mkdir -p $UPSTART_DIR
fi
if [ ! -e $CONFIG_DIR ]; then
mkdir -p $CONFIG_DIR
fi
cp smqueue $INSTALL_DIR
cp smqueue.conf $UPSTART_DIR
if [ $# -ne 1 ]; then
cp smqueue.example.sql $CONFIG_DIR
sqlite3 $CONFIG_DIR/smqueue.db ".read smqueue.example.sql"
else
cp smqueue.example.sql $CONFIG_DIR/
fi
chown -R openbts $CONFIG_DIR
chown -R openbts $INSTALL_DIR
chmod -R a-w $INSTALL_DIR

View File

@ -1,3 +1,19 @@
/*
* Copyright 2008 Free Software Foundation, Inc.
* Copyright 2011, 2013, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program 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.
*/
/*
* Smcommands.cpp - Short Message (SMS) commands ("shortcodes") for OpenBTS.
* Written by John Gilmore, August 2009.
@ -34,7 +50,6 @@
using namespace std;
using namespace SMqueue;
extern ConfigurationTable gConfig;
@ -54,7 +69,7 @@ whiplash_quit (const char *imsi, const char *msgtext, short_code_params *scp)
return SCA_EXEC_SMQUEUE;
}
if (!strncmp("testsave", msgtext+len+1, 4)) {
scp->scp_smq->save_queue_to_file(gConfig.getStr("SC.WhiplashQuit.SaveFile").c_str());
scp->scp_smq->save_queue_to_file(gConfig.getStr("SC.WhiplashQuit.SaveFile").c_str()); // Save on whiplash_quit
scp->scp_reply = new_strdup("Done.");
return SCA_REPLY;
}
@ -78,7 +93,7 @@ shortcode_quick_chk (const char *imsi, const char *msgtext,
{
ostringstream answer;
answer << scp->scp_smq->time_sorted_list.size() << " queued.";
answer << scp->scp_smq->time_sorted_list.size() << " queued."; // No lock okay
scp->scp_reply = new_strdup(answer.str().c_str());
return SCA_REPLY;
}
@ -93,10 +108,11 @@ shortcode_four_one_one (const char *imsi, const char *msgtext,
{
ostringstream answer;
short_msg_p_list::iterator x;
int n = 0, missing = 0, registering = 0, bouncing = 0;
for (x = scp->scp_smq->time_sorted_list.begin();
smq.lockSortedList();
short_msg_p_list::iterator x;
for (x = scp->scp_smq->time_sorted_list.begin(); // locked
x != scp->scp_smq->time_sorted_list.end(); x++) {
n++;
switch (x->state) {
@ -121,10 +137,13 @@ shortcode_four_one_one (const char *imsi, const char *msgtext,
registering++;
break;
default:
;
}
}
default:
break;
} //switch
} // for
smq.unlockSortedList();
answer << n << " queued";
if (missing)
answer << ", " << missing << " unlocatable";
@ -148,7 +167,7 @@ shortcode_four_one_one (const char *imsi, const char *msgtext,
char *newfrom = scp->scp_smq->my_hlr.getCLIDLocal(username);
answer << "phonenum " << newfrom;
time_t now = time(NULL);
time_t now = time(NULL); // Use real time for logging
char timebuf[26+/*slop*/4]; //
answer << ", ";
ctime_r(&now, timebuf);
@ -166,8 +185,8 @@ shortcode_four_one_one (const char *imsi, const char *msgtext,
* Remove a message from the queue, by its tag.
* If first char is "-", don't reply, just do it.
* (this keeps the reply out of the queue, while debugging.)
* If argument is "6000", then delete any queued message with
* timeout greater than 5000 seconds.
* Delete any queued message with
* timeout greater than 5000 seconds (83 minutes).
*/
enum short_code_action
shortcode_zap_queued (const char *imsi, const char *msgtext,
@ -183,14 +202,14 @@ shortcode_zap_queued (const char *imsi, const char *msgtext,
msgtext++;
}
smq.lockSortedList();
if (!strcmp(gConfig.getStr("SC.ZapQueued.Password").c_str(), msgtext)) {
// Delete all messages in queue in NO_STATE state or with
// huge timeouts.
short_msg_p_list::iterator x;
time_t toolate = 5000
+ scp->scp_smq->time_sorted_list.begin()->gettime();
int n = 0;
short_msg_p_list::iterator x;
time_t toolate = SMq::LONGDELETMS // 83 minutes
+ scp->scp_smq->time_sorted_list.begin()->msgettime();
for (x = scp->scp_smq->time_sorted_list.begin();
x != scp->scp_smq->time_sorted_list.end(); x++) {
if (x->state == NO_STATE || toolate <= x->next_action_time) {
@ -211,12 +230,13 @@ shortcode_zap_queued (const char *imsi, const char *msgtext,
answer << "Deleting queued msg '" << msgtext
<< " in state " << sent_msg->state
<< " and timeout "
<< sent_msg->next_action_time - sent_msg->gettime();
<< sent_msg->next_action_time - sent_msg->msgettime();
resplist.splice(resplist.begin(),
scp->scp_smq->time_sorted_list, sent_msg);
resplist.pop_front(); // pop and delete the sent_msg.
}
}
smq.unlockSortedList();
scp->scp_reply = new_strdup(answer.str().c_str());
return noreply? SCA_DONE: SCA_REPLY;
@ -278,6 +298,7 @@ shortcode_register (const char *imsi, const char *msgtext,
default:
answer << "Error: invalid character '" << *p << "' in requested number";
badnum++;
break;
}
}
*q++ = '\0'; // Null-terminate it.
@ -361,25 +382,6 @@ shortcode_register (const char *imsi, const char *msgtext,
enum short_code_action
shortcode_balance (const char *imsi, const char *msgtext,
short_code_params *scp)
{
SubscriberRegistry& hlr = scp->scp_smq->my_hlr;
int accountBalance = 0;
SubscriberRegistry::Status stat = hlr.balanceRemaining(imsi,accountBalance);
if (stat != SubscriberRegistry::SUCCESS) {
LOG(ALERT) << "cannot check account for user " << imsi;
scp->scp_reply = new_strdup("operation failed");
} else {
char rsp[200];
sprintf(rsp,gConfig.getStr("SC.Balance.String").c_str(),accountBalance);
scp->scp_reply = new_strdup(rsp);
}
return SCA_REPLY;
}
/*
* Here is where we list all the functions that we care to make
* available -- along with their phone numbers.
@ -401,8 +403,6 @@ SMqueue::init_smcommands (short_code_map_t *scm)
(*scm)[gConfig.getStr("SC.WhiplashQuit.Code").c_str()] = whiplash_quit;
if (gConfig.defines("SC.SMSC.Code"))
(*scm)[gConfig.getStr("SC.SMSC.Code").c_str()] = shortcode_smsc;
if (gConfig.defines("SC.Balance.Code"))
(*scm)[gConfig.getStr("SC.Balance.Code").c_str()] = shortcode_balance;
// (*scm)["666"] = shortcode_text_access;
}

View File

@ -3,6 +3,7 @@
* Written by John Gilmore, July 2009.
*
* Copyright 2009 Free Software Foundation, Inc.
* Copyright 2014 Range Networks, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -32,11 +33,14 @@
#include <cstdlib> // l64a
#include <arpa/inet.h> // inet_ntop
#include "smnet.h"
#include "smqueue.h"
using namespace std;
namespace SMqueue {
// Because the abort function isn't always accessible in C--?
@ -87,13 +91,15 @@ SMnet::send_dgram(char *buffer, size_t buffsize, char *toaddr,
}
/* Talk to the GSM engine... */
/* Talk to the GSM engine...
* good return true
* bad return false
* */
bool
SMnet::deliver_msg_datagram(SMqueue::short_msg_pending *smp)
{
char *scheme, *host, *port;
int s, i;
// Make sure the text is valid before writing it for debug,
// or delivering it to a handset.
smp->make_text_valid();
@ -174,7 +180,7 @@ SMnet::deliver_msg_datagram(SMqueue::short_msg_pending *smp)
/*
* Network listener for SIP Short Messages.
* Timeout in milliseconds (negative means infinity).
* Timeout in milliseconds (negative means infinity)
*
* Result is <0 if error;
* Result is >0 if buffer contains a received packet.
@ -182,6 +188,8 @@ SMnet::deliver_msg_datagram(SMqueue::short_msg_pending *smp)
* our caller.)
* Result == 0 if caller was interested in writing, there's no received
* packet yet, and it's OK to write now. OR if we timed out.
*
* Reads data in from the network (opned UDP socket on a specific port
*/
int
SMnet::get_next_dgram (char *buffer, size_t bufferlen, int mstimeout)
@ -191,13 +199,21 @@ SMnet::get_next_dgram (char *buffer, size_t bufferlen, int mstimeout)
short revents;
socklen_t addrlen;
size_t recvlength;
LOG(DEBUG) << "Try to load datagram tmo " << mstimeout << " socket fd " << sockets[0].fd;
// verifySocket(1); // Was used to verify socket are working correctly
i = poll_sockets(mstimeout);
if (i < 0) // error
if (i < 0) { // error
LOG(DEBUG) << "Error returned from poll";
return i;
if (i == 0) // timeout
}
if (i == 0) {// timeout
LOG(DEBUG) << "Timeout returned from poll";
return 0;
}
//LOG(DEBUG) << "Got past poll for socket";
for (j = 0; j < numsockets; j++) { // Walk the sockets.
fd = sockets[j].fd;
revents = sockets[j].revents;
@ -211,6 +227,8 @@ SMnet::get_next_dgram (char *buffer, size_t bufferlen, int mstimeout)
// FIXME, TCP and files aren't supported yet
addrlen = sizeof(src_addr);
flags = MSG_DONTWAIT|MSG_TRUNC;
// Read from socket
recvlength = recvfrom(fd, buffer, bufferlen, flags,
(sockaddr *)&src_addr, &addrlen);
if (recvlength < 0) {
@ -267,6 +285,9 @@ SMnet::get_next_dgram (char *buffer, size_t bufferlen, int mstimeout)
* Make one or more sockets and set up to listen on them.
* This function is xxx ought-to-be ipv6-agnostic, and is even
* almost UDP/TCP-agnostic.
* returns
* true got socket
* false no socket
*/
bool
SMnet::listen_on_port(std::string port)
@ -284,13 +305,14 @@ SMnet::listen_on_port(std::string port)
s = getaddrinfo(NULL, (port.c_str()), &myhints, &myaddrs);
if (s != 0) {
LOG(ERR) << "listen_on_port(" << port
<< ") can't get addr/port to listen on";
return -1;
<< ") can't get addr/port to listen on" ;
return false;
}
for (ap = myaddrs; ap != NULL; ap = ap->ai_next) {
int fd, i;
LOG(DEBUG) << "listen_on_port try address " << string_addr (ap, true);
fd = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
if (fd < 0)
@ -299,9 +321,9 @@ SMnet::listen_on_port(std::string port)
i = bind(fd, ap->ai_addr, ap->ai_addrlen);
if (i < 0) {
LOG(ERR) << "listen_on_port(" << port
<< ") can't bind to addr '"
<< ") can't bind (It's okay as long as one port is opened) to addr '"
<< string_addr (ap, true) << "': "
<< strerror(errno);
<< strerror(errno) << " errno:" << errno;
close(fd); // Don't leave it dangling
continue; // Try another
}
@ -312,12 +334,12 @@ SMnet::listen_on_port(std::string port)
#endif
// Now set up our class to poll on, and use, this socket.
add_socket (fd, POLLIN|POLLPRI, ap->ai_family,
add_socket(fd, POLLIN|POLLPRI, ap->ai_family,
ap->ai_socktype, ap->ai_protocol, ap->ai_addr,
ap->ai_addrlen);
// Be slightly verbose here.
LOG(INFO) << "Listening at address '"
<< string_addr (ap, true) << "'.";
LOG(ERR) << "Listening at address '"
<< string_addr (ap, true) << " fd " << fd ;
gotasocket++;
// And keep looping to make several sockets if we can!
}
@ -576,4 +598,35 @@ SMnet::new_call_number()
}
} // namespace SMlistener
/*
* socketnumber 1-N based
*/
void SMnet::verifySocket(int socketNum) {
int optval;
socklen_t optlen;
int rc;
if (!sockets || numsockets == 0 || (socketNum > numsockets )) {
LOG(DEBUG) << "No socket to verify";
return;
}
optlen = sizeof(optval);
rc = getsockopt(sockets[socketNum-1].fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
if (rc == 0) {
if (optlen == sizeof(int)) {
if (optval == 0) {
LOG(DEBUG) << "Socket not valid zero optval";
} else {
LOG(DEBUG) << "Socket valid type " << optval;
}
} else {
LOG(DEBUG) << "Socket not valid optlen wrong " << optval;
}
} else {
LOG(DEBUG) << "getsockopt returned error " << rc;
}
} // SMnet::verifySocket
} // namespace SMQueue

View File

@ -1,9 +1,11 @@
/*
* SMlistener.h - Network SIP handler for Short Messages (SMS's) for OpenBTS.
* Written by John Gilmore, July 2009.
*
* Copyright 2009 Free Software Foundation, Inc.
*
Copyright 2011, 2013, 2014 Range Networks, Inc.
* *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@ -28,6 +30,7 @@
#include "poll.h"
#include <sys/socket.h>
#include <unistd.h>
#include <Logger.h>
namespace SMqueue {
@ -266,6 +269,9 @@ class SMnet {
*/
char *
new_call_number();
void verifySocket(int socketNum);
};

10
smqueue/smqueue.conf Normal file
View File

@ -0,0 +1,10 @@
# smqueue - Range Networks basic SMSC
#
# This service runs smqueue from the point the system is
# started until it is shut down again.
start on stopped rc RUNLEVEL=[2345]
stop on runlevel [!2345]
respawn
exec /OpenBTS/smqueue

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
* SMqueue.h - In-memory queue manager for Short Messages (SMS's) for OpenBTS.
* Written by John Gilmore, July 2009.
*
* Copyright 2009 Free Software Foundation, Inc.
* Copyright 2009, 2014 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -19,9 +19,11 @@
* See the COPYING file in the main directory for details.
*/
#ifndef SM_QUEUE_H
#define SM_QUEUE_H
#include "SmqGlobals.h"
#include <time.h>
//#include <osipparser2/osip_message.h> /* from osipparser2 */
#include <stdlib.h> /* for osipparser2 */
@ -35,8 +37,9 @@
#include "smnet.h" // My network support
#include <SubscriberRegistry.h> // My home location register
#include <Logger.h>
#include "diskbackup.h"
void ProcessReceivedMsg();
// That's awful OSIP has a CR define.
// It clashes with our innocent L2Address::CR().
@ -74,19 +77,19 @@ enum sm_state { // timeout, next-state-if-timeout
NO_STATE,
INITIAL_STATE,
REQUEST_FROM_ADDRESS_LOOKUP,
ASKED_FOR_FROM_ADDRESS_LOOKUP,
ASKED_FOR_FROM_ADDRESS_LOOKUP, //3
AWAITING_TRY_DESTINATION_IMSI,
REQUEST_DESTINATION_IMSI,
REQUEST_DESTINATION_IMSI, // 5
ASKED_FOR_DESTINATION_IMSI,
AWAITING_TRY_DESTINATION_SIPURL,
REQUEST_DESTINATION_SIPURL,
REQUEST_DESTINATION_SIPURL, // 8
ASKED_FOR_DESTINATION_SIPURL,
AWAITING_TRY_MSG_DELIVERY,
REQUEST_MSG_DELIVERY,
ASKED_FOR_MSG_DELIVERY,
AWAITING_TRY_MSG_DELIVERY, // 10
REQUEST_MSG_DELIVERY, // 11
ASKED_FOR_MSG_DELIVERY, // 12
DELETE_ME_STATE,
@ -107,6 +110,7 @@ std::string sm_state_name(enum sm_state astate);
extern bool osip_initialized;
extern struct osip *osipptr;
/* In-memory object representing a Short Message. These are kept as
text strings (as we received them) and only parsed when we need to
process them. This keeps memory usage way down for medium to long
@ -151,8 +155,6 @@ class short_msg {
bool from_relay;
long long timestamp; //timestamp for backup id'ing
short_msg () :
text_length (0),
text (NULL),
@ -165,8 +167,7 @@ class short_msg {
tl_message(NULL),
ms_to_sc(false),
need_repack(true),
from_relay(false),
timestamp(get_msecs())
from_relay(false)
{
}
// Make a short message, perhaps taking responsibility for deleting
@ -183,8 +184,7 @@ class short_msg {
tl_message(NULL),
ms_to_sc(false),
need_repack(true),
from_relay(false),
timestamp(get_msecs())
from_relay(false)
{
if (!use_my_memory) {
text = new char [text_length+1];
@ -211,8 +211,7 @@ class short_msg {
tl_message(NULL),
ms_to_sc(false),
need_repack(true),
from_relay(sm.from_relay),
timestamp(get_msecs())
from_relay(sm.from_relay)
{
if (text_length) {
text = new char [text_length+1];
@ -233,8 +232,7 @@ class short_msg {
rp_data(NULL),
tl_message(NULL),
ms_to_sc(false),
need_repack(false),
timestamp(get_msecs())
need_repack(false)
{
text = new char [text_length+1];
strncpy(text, str.data(), text_length);
@ -255,7 +253,7 @@ class short_msg {
delete [] text;
delete rp_data;
delete tl_message;
};
}
// Pseudo-constructor due to inability to run constructors on
// members of lists.
@ -335,7 +333,7 @@ class short_msg {
}
return true;
}
} // parse
/* Anytime a caller CHANGES the values in the parsed tree of the
message, they MUST call this, to let the caching system
@ -398,7 +396,7 @@ class short_msg {
parsed = NULL;
parsed_is_valid = false;
parsed_is_better = false;
}
} //unparse
std::string get_text() const
{
@ -452,13 +450,16 @@ class short_msg {
case UNSUPPORTED_CONTENT:
default:
return "";
}
}
} // switch
} // get_text
/* Kind of a nasty hack to convert a message as it is going out. Generally from rpdu to text. */
void convert_message(ContentType to) {
convert_content_type = to;
}
void do_not_convert_message() {
convert_content_type = UNSUPPORTED_CONTENT;
}
@ -473,14 +474,13 @@ class short_msg {
extern /*static*/ int (*timeouts[STATE_MAX_PLUS_ONE])[STATE_MAX_PLUS_ONE];
class SMq;
class short_msg_pending: public short_msg {
public:
enum sm_state state; // State of processing
time_t next_action_time; // When to do something different
int retries; // How many times we've retried
// this message.
int cost; // cost of delivering this message, -1 until defined
string service; // service cost name
char srcaddr[16]; // Source address (ipv4 or 6 or ...)
socklen_t srcaddrlen; // Valid length of src address.
char *qtag; // Tag that identifies this msg
@ -505,8 +505,6 @@ class short_msg_pending: public short_msg {
state (NO_STATE),
next_action_time (0),
retries (0),
cost(-1),
service(""),
// srcaddr({0}), // can't seem to initialize an array?
srcaddrlen(0),
qtag (NULL),
@ -522,8 +520,6 @@ class short_msg_pending: public short_msg {
state (NO_STATE),
next_action_time (0),
retries (0),
cost(-1),
service(""),
// srcaddr({0}), // can't seem to initialize an array?
srcaddrlen(0),
qtag (NULL),
@ -538,7 +534,6 @@ class short_msg_pending: public short_msg {
state (NO_STATE),
next_action_time (0),
retries (0),
cost(-1),
// srcaddr({0}), // can't seem to initialize an array?
srcaddrlen(0),
qtag (NULL),
@ -560,8 +555,6 @@ class short_msg_pending: public short_msg {
state (smp.state),
next_action_time (smp.next_action_time),
retries (smp.retries),
cost(smp.cost),
service(smp.service),
// srcaddr({0}), // can't seem to initialize an array?
srcaddrlen(smp.srcaddrlen),
qtag (NULL),
@ -638,18 +631,27 @@ class short_msg_pending: public short_msg {
}
#endif
/* Optimize this later so we don't make so many kernel calls. */
time_t gettime () { return time(NULL); };
time_t msgettime() {
struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
unsigned long time_in_mill =
(tv.tv_sec * 1000UL) + (tv.tv_nsec / 1000000UL) ; // convert tv_sec & tv_usec to millisecond
return time_in_mill;
}
/* Reset the message's state and timeout. Timeout is set based
on the current state and the new state. */
void set_state(enum sm_state newstate) {
next_action_time = gettime() +
next_action_time = msgettime() +
(*SMqueue::timeouts[state])[newstate];
LOG(DEBUG) << "Set state orig " << state << " Newstate " << newstate
<< " Timeout value " << *SMqueue::timeouts[state][newstate];
state = newstate;
/* If we're in a queue, some code in another class is now going
to have to change our queue position. */
};
}
/* Reset the message's state and timeout. Timeout is argument. */
void set_state(enum sm_state newstate, time_t timeout) {
@ -657,7 +659,7 @@ class short_msg_pending: public short_msg {
state = newstate;
/* If we're in a queue, some code in another class is now going
to have to change our queue position. */
};
}
/* Check that the message is valid, and set the qtag and qtaghash
from the message's contents. Result is 0 for valid, or
@ -680,21 +682,6 @@ class short_msg_pending: public short_msg {
bool
check_host_port(char *host, char *port);
/* Check to see if it is an in-network destination. */
bool local_destination(SubscriberRegistry& hlr) const;
/* Check to see if it is from a local user, as opposed to from the gateway. */
bool local_source(SubscriberRegistry& hlr) const;
/* Calculate the cost of delivering this message and set the cost field. */
int set_delivery_cost(SubscriberRegistry& hlr);
/* Check to see if the user has enough credit to send the message. Also sets the cost field. */
bool sufficient_credit(SubscriberRegistry& hlr) const;
/* Debit the account when a message is verified as delivered. */
void debit_account(SubscriberRegistry& hlr) const;
/* Generate a billing record. */
void write_cdr(SubscriberRegistry& hlr) const;
@ -761,10 +748,10 @@ typedef enum short_code_action (*short_func_t)
* Associative map between target phone numbers (short codes) and
* function pointers that implement those numbers.
*/
typedef std::map<std::string,short_func_t> short_code_map_t;
typedef std::map<std::string,short_func_t> short_code_map_t; // Maps description (phone number) to function to call
/* What fills in that map */
void init_smcommands (short_code_map_t *scm);
void init_smcommands(short_code_map_t *scm);
/*
* Main class for SIP Short Message processing.
@ -773,11 +760,37 @@ void init_smcommands (short_code_map_t *scm);
class SMq {
public:
// Put all timeouts in one place
const static int TIMEOUTMS = 5000;
const static int SMSRATELIMITMS = 1000;
const static int LONGDELETMS = 5000000; // 83 minutes Used by SC.ZapQueued.Password
const static int INCREASEACKEDMSGTMOMS = 60000; // 5 minutes
void InitBeforeMainLoop();
void CleaupAfterMainreaderLoop();
void InitInsideReaderLoop();
/* A list of all messages we know about, sorted by time of next
action (assuming nothing arrives to change our mind before that
time). */
short_msg_p_list time_sorted_list;
std::string savefile; //SMq
bool please_re_exec;
pthread_mutexattr_t mutexSLAttr;
pthread_mutex_t sortedListMutex;
void unlockSortedList() {
// LOG(DEBUG) << "UNLOCK"; // debug opnly
pthread_mutex_unlock(&sortedListMutex);
}
void lockSortedList() {
// LOG(DEBUG) << "LOCK"; // debug only
pthread_mutex_lock(&sortedListMutex);
}
/* We may later want other accessors for faster access to various
messages when things DO arrive. For now, linear search! */
@ -788,8 +801,6 @@ class SMq {
messages and looking up their return and destination addresses. */
SubscriberRegistry my_hlr;
SQLiteBackup my_backup;
/* Where to send SMS's that we can't route locally. */
std::string global_relay;
std::string global_relay_port;
@ -814,10 +825,15 @@ class SMq {
/* Set this to true when you want main loop to stop. */
bool stop_main_loop;
/* Set this to true when you want the program to re-exec itself
instead of terminating after the main loop stops. */
bool reexec_smqueue;
// Input from command line
int argc;
char **argv;
/* Constructor */
SMq () :
time_sorted_list (),
@ -834,18 +850,31 @@ class SMq {
stop_main_loop (false),
reexec_smqueue (false)
{
// We need recursive attribute set
int mStatus;
mStatus = pthread_mutexattr_init(&mutexSLAttr);
if (mStatus != 0) { LOG(DEBUG) << "Mutex pthread_mutexattr_init error " << mStatus; }
pthread_mutexattr_settype(&mutexSLAttr, PTHREAD_MUTEX_RECURSIVE);
if (mStatus != 0) { LOG(DEBUG) << "Mutex pthread_mutexattr_settype error " << mStatus; }
pthread_mutex_init(&sortedListMutex, &mutexSLAttr);
if (mStatus != 0) { LOG(DEBUG) << "Mutex pthread_mutex_init error " << mStatus; }
my_hlr.init();
my_backup.init();
}
/* Destructor */
~SMq() {
pthread_mutex_destroy(&sortedListMutex);
}
// Override operator= so -Weffc++ doesn't complain
// *DISABLE* assignments by making the = operation private.
private:
SMq & operator= (const SMq &rvalue);
public:
/* Destructor */
/* Set my own IP address, since I can't tell how I look to others. */
void set_my_ipaddress(std::string myip) {
my_ipaddress = myip;
@ -858,7 +887,7 @@ class SMq {
void set_my_2nd_ipaddress(std::string myip) {
my_2nd_ipaddress = myip;
// Point to it for message validity checking.
// NOTE: that copy shares same storage as this one.
// NOTE: that copy shares same storage as this one.LOG(DEBUG) << "Run once a minute stuff"
short_msg_pending::smp_my_2nd_ipaddress = myip.c_str();
}
@ -896,23 +925,14 @@ class SMq {
/* Convert a short_msg to a given content type */
//void convert_message(short_msg_pending *qmsg, short_msg::ContentType toType);
/* handle an incoming datagram */
/* timestamp is used if you want to set the timestamp for an incoming message
0 will cause a new timestamp to be generated */
void handle_datagram(int len, char* buffer, long long timestamp, bool insert=true);
// Main loop listening for dgrams and processing them.
void main_loop();
void main_loop(int tmo);
/* If nothing happens for a while, handle that. */
void process_timeout();
/* Verify that sufficient funds exist to send a particular message. */
enum sm_state verify_funds(short_msg_p_list::iterator& qmsg);
/* Send a SIP response to acknowledge reciept of a short msg. */
void respond_sip_ack(int errcode, short_msg_pending *smp,
char *netaddr, size_t netaddrlen);
void respond_sip_ack(int errcode, short_msg_pending *smp, char *netaddr, size_t netaddrlen);
/*
* Originate a short message
@ -1017,22 +1037,39 @@ class SMq {
// new messages as a 1-entry short_msg_p_list and then move
// them to the real list. Note that this moves the message's list
// entry itself off the original list (which can then be discarded).
// Push_front only does a copy so use splice ??
void insert_new_message(short_msg_p_list &smp) {
lockSortedList();
time_sorted_list.splice (time_sorted_list.begin(), smp);
time_sorted_list.begin()->set_state (INITIAL_STATE); // Note set state can move the entries in the queue
// time_sorted_list.begin()->timeout = 0; // it is already
// Low timeout will cause this msg to be at front of queue.
unlockSortedList();
debug_dump(); //svgfix
ProcessReceivedMsg();
}
// This version lets the initial state be set.
void insert_new_message(short_msg_p_list &smp, enum sm_state s) {
LOG(DEBUG) << "Insert message into queue 2";
lockSortedList();
time_sorted_list.splice (time_sorted_list.begin(), smp);
time_sorted_list.begin()->set_state (s);
// time_sorted_list.begin()->timeout = 0; // it is already
// Low timeout will cause this msg to be at front of queue.
unlockSortedList();
debug_dump(); //svgfix
ProcessReceivedMsg();
}
// This version lets the state and timeout be set.
void insert_new_message(short_msg_p_list &smp, enum sm_state s,
time_t t, bool insert = true) {
if (insert && !my_backup.insert(smp.begin()->timestamp, smp.begin()->text)){
LOG(INFO) << "Unable to backup message: " << time_sorted_list.begin()->timestamp;
}
void insert_new_message(short_msg_p_list &smp, enum sm_state s, time_t t) {
LOG(DEBUG) << "Insert message into queue 3";
lockSortedList();
time_sorted_list.splice (time_sorted_list.begin(), smp);
time_sorted_list.begin()->set_state (s, t);
}
// This version lets the initial state be set.
void insert_new_message(short_msg_p_list &smp, enum sm_state s, bool insert=true) {
insert_new_message(smp, s, 0, insert);
}
//Basic version
void insert_new_message(short_msg_p_list &smp, bool insert=true) {
insert_new_message(smp, INITIAL_STATE, insert);
unlockSortedList();
debug_dump(); //svgfix
ProcessReceivedMsg();
}
/* Debug dump of the queue and the SMq class in general. */
@ -1056,6 +1093,7 @@ class SMq {
*/
void set_state(short_msg_p_list::iterator sm, enum sm_state newstate) {
short_msg_p_list temp;
lockSortedList();
/* Extract the current sm from the time_sorted_list */
temp.splice(temp.begin(), time_sorted_list, sm);
sm->set_state(newstate);
@ -1071,7 +1109,8 @@ class SMq {
break;
}
}
};
unlockSortedList();
} // set_state
/*
* When we reset the state and timestamp of a message,
@ -1081,8 +1120,8 @@ class SMq {
* With multisets you can't splice an element out while keeping the
* element... etc.
*/
void set_state(short_msg_p_list::iterator sm, enum sm_state newstate,
time_t timestamp) {
void set_state(short_msg_p_list::iterator sm, enum sm_state newstate, time_t timestamp) {
lockSortedList();
short_msg_p_list temp;
/* Extract the current sm from the time_sorted_list */
temp.splice(temp.begin(), time_sorted_list, sm);
@ -1099,7 +1138,8 @@ class SMq {
break;
}
}
};
unlockSortedList();
} // set_state
/* Save the queue to a file; read it back from a file.
Reading a queue file doesn't delete things that might already
@ -1109,9 +1149,12 @@ class SMq {
save_queue_to_file(std::string qfile);
bool
read_queue_from_file(std::string qfile);
};
}; // SMq class
} // namespace SMqueue
extern SMqueue::SMq smq;
#endif

View File

@ -2,7 +2,7 @@
* SMSC.h - SMS Center implementation for OpenBTS.
* Written by Alexander Chemeris, 2010.
*
* Copyright 2010 Free Software Foundation, Inc.
* Copyright 2010, 2014 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -181,7 +181,7 @@ short_code_action sendSIP_init_text(const char *imsi,
void pack_tpdu(short_msg_p_list::iterator &smsg)
{
// Pack RP-DATA to bitstream
RLFrame RPDU_new(smsg->rp_data->bitsNeeded());
RLFrame RPDU_new(BitVector(smsg->rp_data->bitsNeeded()));
smsg->rp_data->write(RPDU_new);
LOG(DEBUG) << "New RLFrame: " << RPDU_new;
@ -274,46 +274,6 @@ short_code_action submitSMS(const char *imsi, const TLSubmit& submit,
LOG(INFO) << "from " << imsi << " message: " << submit;
const TLAddress& address = submit.DA();
// Hey! You can get to the HLR through the scp argument!
SubscriberRegistry& hlr = scp->scp_smq->my_hlr;
// Is this message going to a short code?
// Short codes costs are special cases and will be checked im the short code handlers thmeselves.
bool isShortCode = (short_code_map.find(address.digits()) != short_code_map.end());
// TODO: If this is a short code, and we know that the cost will be 0, why waste time hitting the subscriber registry? -DCK
// That means, don't look up the service, and don't check to see if any user is prepaid.
// FIXME: There are some helper functions in smqueue.cpp. Why not use those? Or move them somewhere to be used commonly. -DCK
// Get the delivery cost.
string service;
const char * dialedNumber = address.digits();
if (hlr.getIMSI(dialedNumber)) service = gConfig.getStr("ServiceType.Local");
else service = gConfig.getStr("ServiceType.Networked");
int cost = hlr.serviceCost(service.c_str());
if (isShortCode) cost = 0;
if (cost>=0) scp->scp_qmsg_it->cost = cost;
else { LOG(ALERT) << "cannot get cost for service type " << service; }
scp->scp_qmsg_it->service = service;
// If the message is NOT inbound from the relay, bill
if (!scp->scp_qmsg_it->from_relay) {
// Check the subscriber's balance now.
bool prepaid;
hlr.isPrepaid(imsi,prepaid);
int accountBalance = 0;
SubscriberRegistry::Status stat = hlr.balanceRemaining(imsi,accountBalance);
if (stat != SubscriberRegistry::SUCCESS) { LOG(ALERT) << "cannot check account for user " << imsi; }
if (prepaid && cost!=0 && accountBalance<cost) {
ostringstream os;
// TODO: Make customizable
os << "Account balance of " << accountBalance << " too low for service cost of " << cost << ".";
scp->scp_reply = new_strdup(os.str().c_str());
return SCA_REPLY;
}
}
//#if 0
//This is broken under Unbuntu becasue of changes in the "mail" program.
@ -330,7 +290,7 @@ short_code_action submitSMS(const char *imsi, const TLSubmit& submit,
*term = '\0';
char* SMTPPayload = term+1;
// Get the sender's E.164 to put in the subject line.
char* clid = hlr.getCLIDLocal(imsi);
char* clid = scp->scp_smq->my_hlr.getCLIDLocal(imsi);
char subjectLine[200];
if (!clid) sprintf(subjectLine,"from %s",imsi);
else {
@ -350,7 +310,7 @@ short_code_action submitSMS(const char *imsi, const TLSubmit& submit,
// And whether of not we can resolve the destination, and a global relay does not exist,
// AND the message is not to a shortcode.
if (gConfig.getStr("SIP.GlobalRelay.IP").length() == 0 && gConfig.getStr("SMS.HTTPGateway.URL").length() != 0 &&
!destinationNumber && !isShortCode)
!destinationNumber)
// If there is an external HTTP gateway, use it.
return sendHTTP(address.digits(), body);

View File

@ -2,7 +2,7 @@
* SMSC.h - SMS Center implementation for OpenBTS.
* Written by Alexander Chemeris, 2010.
*
* Copyright 2010 Free Software Foundation, Inc.
* Copyright 2010, 2014 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by

@ -1 +1 @@
Subproject commit 3d0dbe8e7a819585cac5064beabe9b22f8d47235
Subproject commit effc8fe4744285c07e3710ab97231537a27b7997

View File

@ -1,4 +0,0 @@
SR http://wush.net/svn/range/software/public/subscriberRegistry/trunk
CommonLibs http://wush.net/svn/range/software/public/CommonLibs/trunk
sqlite3 http://wush.net/svn/range/software/public/sqlite3/trunk

View File

@ -31,12 +31,14 @@ noinst_PROGRAMS = \
smtest_SOURCES = \
smtest.cpp
smtest_LDADD = \
$(COMMON_LA)
$(COMMON_LA) \
$(SQLITE_LA)
smrelaytest_SOURCES = \
smrelaytest.cpp
smrelaytest_LDADD = \
$(COMMON_LA)
$(COMMON_LA) \
$(SQLITE_LA)
sminterface_SOURCES = \
sminterface.cpp

View File

@ -1,6 +1,6 @@
/*
* Copyright 2011 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 Range Networks, Inc.
* Copyright 2012-2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
@ -29,6 +29,10 @@
#include <Sockets.h>
// (pat 8-9-2013) Unfortunately we need a default config to eliminate link errors.
#include <Configuration.h>
ConfigurationTable gConfig("/etc/OpenBTS/smqueue.db","smrelaytest");
/** Submit an SMS for delivery.
* @return The server return code.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 Range Networks, Inc.
* Copyright 2012-2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.

View File

@ -1,7 +1,27 @@
/**
*
*
*/
/*
* Copyright 2012-2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "smtest.h"
@ -10,6 +30,10 @@
#include <Sockets.h>
// (pat 8-9-2013) Unfortunately we need a default config to eliminate link errors.
#include <Configuration.h>
ConfigurationTable gConfig("/etc/OpenBTS/smqueue.db","smtest");
/** Submit an SMS for delivery.
* @return The server return code.
*/

View File

@ -1,8 +1,28 @@
/**
*
*
*
*/
/*
* Copyright 2012-2014 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef smtest_h
#define smtest_h