По немногочисленным просьбам трудящихся я расскажу как заворачивать GSM SMS из sip_dongle модуля для Asterisk в sip messaging с последующей маршрутизацией. Есть центральный узел Asterisk, на котором живет логика и пользователи (extensions). К нему подключаются через PJSIP другие оконечные Asterisk`и на которых висит по несколько GSM модемов. Одна из задач: принимать и отправлять GSM SMS сообщения правильно маршрутизируя их по номеру получателя. Вторая подзадача: дать нашим пользователям (extensions) возможность слать друг другу текстовые сообщения. Итак. Что тут сложного и в чем подвох? Когда у вас 1 модем и 1 extension все очень просто. Когда у вас 2 модема и 1 extension задача все еще простая.Когда у вас “многое ко многим” — вот тут и кроется основная сложность. Т.е. нам нужно не просто понимать на какой конкретно модем какому конкретно Asterisk`у передать исходящее SMS, но и куда направить входящее из GSM сети сообщение. А так же что делать, если мы внутри себя не можем сообщения доставить. Обозначения: gsmru 10.8.0.11 — оконечный сервер Asterisk на котором живут модемы 10.8.0.10 — центральный сервер Asterisk на котором крутится вся логика 101;102;103 - пользователи (extensions) sip - протокол ходит по 80му порту (так исторически сложилось) Начнем разворачивать цепочку от оконечного Asterisk (gsmru) с модемами в сторону центрального сервера. Это канал приема сообщений и проще его объяснять именно так. Работать с SMS можно по разному, но в моем случае я использую sqlite, который у меня /var/lib/asterisk/smsdb.sqlite3. Это сделано так чтобы можно было легко оперировать сообщениями, создавать очереди доставки в обе стороны и не переживать за всякие проблемы вида «я записал что-то в файл и мне нужно успеть это вычитать пока туда не записалось следующее, а заодно проверить что там нет «патча Бармина». Поэтому в dongle.conf честно вписываемsmsdb=/var/lib/asterisk/smsdbcsmsttl=600и радуемся результату. Еще не забываем выставить autodeletesms=yes что бы память модема не забивалась и очередь не застревала (мы ж и так все в базу положили). Все просто: CREATE TABLE incoming (key VARCHAR(256), seqorder INTEGER, expiration TIMESTAMP DEFAULT CURRENT_TIMESTAMP, message VARCHAR(256), PRIMARY KEY(key, seqorder)) CREATE TABLE outgoing_msg (dev VARCHAR(256), dst VARCHAR(255), cnt INTEGER, expiration TIMESTAMP, srr BOOLEAN, payload BLOB) CREATE TABLE outgoing_part (key VARCHAR(256), msg INTEGER, status INTEGER, PRIMARY KEY(key)) CREATE TABLE outgoing_ref (key VARCHAR(256), refid INTEGER, PRIMARY KEY(key)) CREATE INDEX incoming_key ON incoming(key) CREATE INDEX outgoing_part_msg ON outgoing_part(msg На том же самом оконечном Asterisk (gsmru) в extensions.conf создаем правила обработки входящих сообщений.  Напоминаю: 10.8.0.10 — центральный сервер Asterisk, gsmru — наш оконечный узл Asterisk Прописывам на оконочном Asterisk (gsmru) в extensions.conf: exten => sms,1,Verbose(Incoming SMS from ${CALLERID(num)} to ${DONGLENAME} ${BASE64_DECODE(${SMS_BASE64})}) same = n,Set(MESSAGE(body)=${BASE64_DECODE(${SMS_BASE64})}) same = n,Set(MSGSENDER=${CALLERID(num)}) same = n,GotoIf($["${DONGLENAME}"="dongle0"]?smsFromDongle0) same = n,GotoIf($["${DONGLENAME}"="dongle1"]?smsFromDongle1) same = n,GotoIf($["${DONGLENAME}"="dongle2"]?smsFromDongle2) same = n(smsFromDongle0),NoOp("Forwarding to 101") same = n,Set(NDEST=pjsip:gsmru/sip:101@10.8.0.10:80) same = n,MessageSend(${NDEST},${MSGSENDER}) same = n,Hangup() same = n(smsFromDongle1),NoOp("Forwarding to 102") same = n,Set(NDEST=pjsip:gsmru/sip:102@10.8.0.10:80) same = n,MessageSend(${NDEST},${MSGSENDER}) same = n,Hangup() same = n(smsFromDongle2),NoOp("Forwarding to 103") same = n,Set(NDEST=pjsip:gsmru/sip:103@10.8.0.10:80) same = n,MessageSend(${NDEST},${MSGSENDER}) same = n,Hangup(); Тут все очень просто: сообщаем в консоль что у нас входящее сообщение, печатаем туда же его текст, смотрим от какого устройства и направляем в нужную сторону.  Примерно так же можно направить на группу что бы сообщение «разлетелось всем».   Сообщене уже в виде sip message летит на центральный узел 10.8.0.10 А там его ждет описание оконечного узла в pjsip.conf type=endpointtransport=transport-tcpcontext=incoming-callsmessage_context=incoming-smsdisallow=allallow=ulaw,alaw,opusoutbound_auth=gsmru-authaors=gsmrulanguage=ru Ну и что бы этот контекст не пропадал даром, в extensions.conf имеем: ;incoming sms from Gsm Gateways exten =_1.,1,Verbose(1, "Incoming SMS from ${CALLERID(num)} GSM Gateway to ${EXTEN}") same = n,NoOp(To ${MESSAGE(to)}) same = n,NoOp(From ${MESSAGE(from)}) same = n,NoOp(Body ${MESSAGE(body)}) same = n,MessageSend(${MESSAGE(to)},${MESSAGE(from)}) same = n,NoOp(Send status is ${MESSAGE_SEND_STATUS}) same = n,GotoIf($["${MESSAGE_SEND_STATUS}" != "SUCCESS"]?handlefailedmsg) same = n,Hangup(); Handle failed messaging same = n(handlefailedmsg),NoOp(Sending error to user) same = n,Set(SRC=${MESSAGE(from)}) same = n,Set(DST=${MESSAGE(to)}) same = n,Set(MSG=${MESSAGE(body)})   same = n,Set(MESSAGE(body)="[${STRFTIME(${EPOCH},,%d%m%Y-%H:%M:%S)}] Your message to ${EXTEN} has failed. Sending when available") same = n,Set(ME_1=${CUT(MESSAGE(from),<,2)}) same = n,Set(ACTUALFROM=${CUT(ME_1,@,1)}) same = n,MessageSend(${ACTUALFROM},ServiceCenter); same = n,GotoIf($["${INQUEUE}" != "1"]?startq) same = n,Hangup() Все, магия случилась — сообщение улетело в виде sip mesage в клиентское ПО\Оборудование. Иными словами, если послать sms на номер модема, оно появится в программе. Я уже говорил что не использую аппаратные телефоны, так что тут «не копенгаген», а в Linphone глюк выводит пустое сообщение. Так что на Android я использую PortSip. Как нам теперь отправлять SMS во внешний мир? Тут все чуть сложнее и мы пойдем от центрального сервера к модему.Прописываем на центральном сервере в pjsip.conf: [endpoint-internal](!)type = endpointcontext = defaultmessage_context = outgoing-smsallow = !all,alaw,ulaw,opus,h264,vp8,vp9direct_media = notrust_id_outbound = yesdevice_state_busy_at = 1dtmf_mode = rfc4733media_encryption = sdesrewrite_contact = yes Теперь маршрутизация для центрального сервера в extensions.conf: exten = _+7.,1,Verbose(1, "Outgoing SMS from ${CALLERID(num)} GSM Gateway to ${EXTEN}") same = n,NoOp(To ${MESSAGE(to)}) same = n,NoOp(From ${MESSAGE(from)}) same = n,NoOp(Body ${MESSAGE(body)}) same = n,Set(TO= ${MESSAGE(to)}) same = n,Set(BUF= ${CUT(TO,@,1)}) same = n,NoOp(BUF ${BUF}) same = n,Set(NDEST=pjsip:gsmru/sip:${CUT(BUF,:,2)}@10.8.0.11:80) same = n,NoOp(NDEST ${NDEST}) same = n,Set(BUF1=${CUT(TO,<sip:,2)})     same = n,NoOp(BUF1 ${BUF1}) same = n,Set(BUF2=${STRREPLACE(BUF1:4,>,)}) same = n,NoOp(BUF2 ${BUF2}) same = n,Set(BUF3=${CUT(BUF2,@,1)}) same = n,NoOp(BUF3 ${BUF3}) same = n,GotoIf(${LEN(${BUF3})}=0?:sendsms) same = n,Set(NDEST=pjsip:gsmru/sip:${BUF3}@10.8.0.11:80) same = n,NoOp(NDEST ${NDESTD}) same = n(sendsms),MessageSend(${NDEST},${MESSAGE(from)}) same = n,Hangup exten = _8.,1,Verbose(1, "Outgoing SMS from ${CALLERID(num)} GSM Gateway to ${EXTEN}") same = n,NoOp(To ${MESSAGE(to)}) same = n,NoOp(From ${MESSAGE(from)}) same = n,NoOp(Body ${MESSAGE(body)}) same = n,Set(TO= ${MESSAGE(to)}) same = n,Set(BUF= ${CUT(TO,@,1)}) same = n,NoOp(BUF ${BUF}) same = n,Set(NDEST=pjsip:gsmru/sip:${CUT(BUF,:,2)}@10.8.0.11:80) same = n,NoOp(NDEST ${NDEST}) same = n,Set(BUF1=${CUT(TO,<sip:,2)})     same = n,NoOp(BUF1 ${BUF1}) same = n,Set(BUF2=${STRREPLACE(BUF1:4,>,)}) same = n,NoOp(BUF2 ${BUF2}) same = n,Set(BUF3=${CUT(BUF2,@,1)}) same = n,NoOp(BUF3 ${BUF3}) same = n,GotoIf(${LEN(${BUF3})}=0?:sendsms) same = n,Set(NDEST=pjsip:gsmru/sip:${BUF3}@10.8.0.11:80) same = n,NoOp(NDEST ${NDESTD}) same = n(sendsms),MessageSend(${NDEST},${MESSAGE(from)}) same = n,Hangup Сообщение мы смаршрутизировали и даже забуферизировали если не смогли отправить (ну там канал лег или деньги на карточке кончились). Теперь на нашем оконечном Asterisk gsmru в pjsip.conf создаем описание входящего аккаунта: type=endpointcontext=defaultmessage_context=outgoing-smsdisallow=allallow=ulaw,alawtransport=transport-tcpauth=gsmruaors=gsmru И на том же оконечном gsmru задаем маршрутизацию в extensions.conf: exten = _+X.,1,Verbose(1, "Outgoing SMS from ${CALLERID(num)} to ${EXTEN}.") same = n,NoOp(To ${MESSAGE(to)}) same = n,NoOp(From ${MESSAGE(from)}) same = n,NoOp(Body ${MESSAGE(body)}) same = n,Set(TO=${MESSAGE(to)}) same = n,Set(FROM=${CUT(MESSAGE(from),<,2)}) same = n,Set(BUF=${CUT(TO,@,1)}) same = n,Set(DEST=${CUT(BUF,:,2)}) same = n,NoOp(DEST=${DEST}) same = n,GotoIf($["${FROM}"="sip:101@SIPDOMAIN>"]?sendSmsDongle0) same = n,GotoIf($["${FROM}"="sip:102@SIPDOMAIN>"]?sendSmsDongle1) same = n,GotoIf($["${FROM}"="sip:103@SIPDOMAIN>"]?sendSmsDongle2) same = n(sendSmsDongle0),DongleSendSMS(dongle0,${DEST},"${MESSAGE(body)}",1140,yes,"magicid") same = n,Hangup() same = n(sendSmsDongle1),DongleSendSMS(dongle1,${DEST},"${MESSAGE(body)}",1140,yes,"magicid") same = n,Hangup() same = n(sendSmsDongle2),DongleSendSMS(dongle2,${DEST},"${MESSAGE(body)}",1140,yes,"magicid") same = n,Hangup()exten = _X.,1,Verbose(1, "Outgoing SMS from ${CALLERID(num)} to ${EXTEN}.") same = n,NoOp(To ${MESSAGE(to)}) same = n,NoOp(From ${MESSAGE(from)}) same = n,NoOp(Body ${MESSAGE(body)}) same = n,Set(TO=${MESSAGE(to)}) same = n,Set(FROM=${CUT(MESSAGE(from),<,2)}) same = n,Set(BUF=${CUT(TO,@,1)}) same = n,Set(DEST=${CUT(BUF,:,2)}) same = n,NoOp(DEST=${DEST}) same = n,GotoIf($["${FROM}"="sip:101@SIPDOMAIN>"]?sendSmsDongle0) same = n,GotoIf($["${FROM}"="sip:102@SIPDOMAIN>"]?sendSmsDongle1) same = n,GotoIf($["${FROM}"="sip:103@SIPDOMAIN>"]?sendSmsDongle2) same = n(sendSmsDongle0),DongleSendSMS(dongle0,${DEST},"${MESSAGE(body)}",1140,yes,"magicid") same = n,Hangup() same = n(sendSmsDongle1),DongleSendSMS(dongle1,${DEST},"${MESSAGE(body)}",1140,yes,"magicid") same = n,Hangup() same = n(sendSmsDongle2),DongleSendSMS(dongle2,${DEST},"${MESSAGE(body)}",1140,yes,"magicid") И вуаля — сообщение уйдет в GSM сеть! Я использую PJSIP и ничего не знаю про sip. Ну как бы у нас 2к21 на дворе, пора бы уже двигаться в будущее. Да, я использую транспорт TCP по 80му порту. Это не влияет на рассмотренный вопрос про SMS. Если у вас много стран\городов или много префиксов номера - для них для всех нужно повторять блоки маршрутизации, так же как и для звонков. Обязательна поддержка SRTP на клиенте (оно включено на сервере). На клиенте DTMF нужно выставить в RFC2833.