📄 mtp3d.c
字号:
/* mtp3d.c - mtp2/mtp3 daemon
* Author: Anders Baekgaard <ab@dicea.dk>
* This work is derived from chan_ss7, see copyright below.
*/
/*
* This file is part of chan_ss7.
*
* chan_ss7 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* chan_ss7 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with chan_ss7; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <asterisk/strings.h>
#include <asterisk/utils.h>
#include "config.h"
#include "lffifo.h"
#include "mtp.h"
#include "isup.h"
#include "transport.h"
#include "utils.h"
#include "aststubs.h"
#include "mtp3io.h"
#undef inet_ntoa
static int do_pid = 0;
static struct lffifo **mtp_send_fifo;
#define MAXCLIENTS 32
int n_registry;
struct {
int ss7_protocol;
int host_ix;
struct sockaddr_in client;
int peerfd;
struct link* link;
union {
struct {
int subsystem;
} sccp;
};
} registry[MAXCLIENTS];
void l4sccp_inservice(struct link* link);
void l4sccp_event(struct mtp_event* event);
void l4sccp_link_status_change(struct link* link, int up);
void l4isup_inservice(struct link* link);
void l4isup_event(struct mtp_event* event);
void l4isup_link_status_change(struct link* link, int up);
static struct lffifo *mtp_control_fifo = NULL;
/* This is the MTP2/MTP3 thread, which runs at high real-time priority
and is careful not to wait for locks in order not to loose MTP
frames. */
static pthread_t mtp_thread = AST_PTHREADT_NULL;
/* This is the monitor thread which mainly handles scheduling/timeouts. */
static int mtp_thread_running = 0;
/* This is the monitor thread which mainly handles scheduling/timeouts. */
static pthread_t monitor_thread = AST_PTHREADT_NULL;
static int monitor_running = 0;
/* State for raw dumps. */
AST_MUTEX_DEFINE_STATIC(dump_mutex);
static FILE *dump_in_fh = NULL;
static FILE *dump_out_fh = NULL;
static int dump_do_fisu, dump_do_lssu, dump_do_msu;
static void dump_pcap(FILE *f, struct mtp_event *event)
{
unsigned int sec = event->dump.stamp.tv_sec;
unsigned int usec = event->dump.stamp.tv_usec - (event->dump.stamp.tv_usec % 1000) +
event->dump.slinkno*2 + /* encode link number in usecs */
event->dump.out /* encode direction in/out */;
fwrite(&sec, sizeof(sec), 1, f);
fwrite(&usec, sizeof(usec), 1, f);
fwrite(&event->len, sizeof(event->len), 1, f);
fwrite(&event->len, sizeof(event->len), 1, f);
fwrite(event->buf, 1, event->len, f);
fflush(f);
}
static void init_pcap_file(FILE *f)
{
unsigned int magic = 0xa1b2c3d4; /* text2pcap does this */
unsigned short version_major = 2;
unsigned short version_minor = 4;
unsigned int thiszone = 0;
unsigned int sigfigs = 0;
unsigned int snaplen = 102400;
unsigned int linktype = 140;
fwrite(&magic, sizeof(magic), 1, f);
fwrite(&version_major, sizeof(version_major), 1, f);
fwrite(&version_minor, sizeof(version_minor), 1, f);
fwrite(&thiszone, sizeof(thiszone), 1, f);
fwrite(&sigfigs, sizeof(sigfigs), 1, f);
fwrite(&snaplen, sizeof(snaplen), 1, f);
fwrite(&linktype, sizeof(linktype), 1, f);
}
static int start_mtp_thread(void)
{
return start_thread(&mtp_thread, mtp_thread_main, &mtp_thread_running, 15);
}
static void stop_mtp_thread(void)
{
mtp_thread_signal_stop();
stop_thread(&mtp_thread, &mtp_thread_running);
}
static void process_event(struct mtp_event* event)
{
switch(event->typ) {
case MTP_EVENT_ISUP:
l4isup_event(event);
break;
case MTP_EVENT_SCCP:
l4sccp_event(event);
break;
case MTP_EVENT_LOG:
ast_log(event->log.level, event->log.file, event->log.line,
event->log.function, "%s", event->buf);
break;
case MTP_EVENT_STATUS:
{
struct link* link = event->status.link;
char* name = link ? link->name : "(peer)";
switch(event->status.link_state) {
case MTP_EVENT_STATUS_LINK_UP:
l4isup_link_status_change(link, 1);
l4sccp_link_status_change(link, 1);
ast_log(LOG_WARNING, "MTP is now UP on link '%s'.\n", name);
break;
case MTP_EVENT_STATUS_LINK_DOWN:
l4isup_link_status_change(link, 0);
l4sccp_link_status_change(link, 0);
ast_log(LOG_WARNING, "MTP is now DOWN on link '%s'.\n", name);
break;
case MTP_EVENT_STATUS_INSERVICE:
ast_log(LOG_WARNING, "MTP is now INSERVICE for linkset '%s'.\n", link->linkset->name);
l4isup_inservice(link);
l4sccp_inservice(link);
break;
default:
ast_log(LOG_NOTICE, "Unknown event type STATUS (%d), "
"not processed.\n", event->status.link_state);
}
}
break;
case MTP_EVENT_DUMP:
{
FILE *dump_fh;
ast_mutex_lock(&dump_mutex);
if(event->dump.out) {
dump_fh = dump_out_fh;
} else {
dump_fh = dump_in_fh;
}
if(dump_fh != NULL) {
if(event->len < 3 ||
( !(event->buf[2] == 0 && !dump_do_fisu) &&
!((event->buf[2] == 1 || event->buf[2] == 2) && !dump_do_lssu) &&
!(event->buf[2] > 2 && !dump_do_msu)))
dump_pcap(dump_fh, event);
}
ast_mutex_unlock(&dump_mutex);
}
break;
default:
ast_log(LOG_NOTICE, "Unexpected mtp event type %d.\n", event->typ);
}
}
/* Monitor thread main loop.
Monitor reads events from the realtime MTP thread, and processes them at
non-realtime priority. It also handles timers for ISUP etc.
*/
static void *monitor_main(void *data) {
int res;
struct pollfd fds[1];
struct lffifo *receive_fifo = mtp_get_receive_fifo();
ast_verbose(VERBOSE_PREFIX_3 "Starting monitor thread, pid=%d.\n", getpid());
fds[0].fd = get_receive_pipe();
fds[0].events = POLLIN;
while(monitor_running) {
int timeout = 20;
res = poll(fds, 1, timeout);
if(res < 0) {
if(errno == EINTR) {
/* Just try again. */
} else {
ast_log(LOG_ERROR, "poll() failure, errno=%d: %s\n",
errno, strerror(errno));
}
} else if(res > 0) {
/* Events waiting in the receive buffer. */
unsigned char dummy[512];
unsigned char eventbuf[MTP_EVENT_MAX_SIZE];
struct mtp_event *event;
/* Empty the pipe before pulling from fifo. This way the race
condition between mtp and monitor threads may cause spurious
wakeups, but not loss/delay of messages. */
read(fds[0].fd, dummy, sizeof(dummy));
/* Process all available events. */
while((res = lffifo_get(receive_fifo, eventbuf, sizeof(eventbuf))) != 0) {
if(res < 0) {
ast_log(LOG_ERROR, "Yuck! oversized frame in receive fifo, bailing out.\n");
return NULL;
}
event = (struct mtp_event *)eventbuf;
process_event(event);
}
}
}
return NULL;
}
void l4sccp_inservice(struct link* link)
{
}
void l4sccp_event(struct mtp_event* event)
{
printf("l4sccp_event\n");
unsigned char* buf = event->buf;
int dpc = buf[0] | ((buf[1] & 0x3f) << 8);
int opc = ((buf[1] & 0xc0) >> 6) | (buf[2] << 2) | ((buf[3] & 0x0f) << 10);
int typ = buf[4];
int n;
printf("SCCP event, OPC=%d, DPC=%d, typ=%d\n", opc, dpc, typ);
for (n = 0; n < n_registry; n++) {
if ((registry[n].ss7_protocol == SS7_PROTO_SCCP) /* xxx check dpc/subsystem */) {
event->sccp.slinkix = event->sccp.slink->linkix;
mtp3_reply(registry[n].peerfd, (void*) event, sizeof(*event)+event->len, (const struct sockaddr*) ®istry[n].client, sizeof(registry[n].client));
return;
}
}
if (n == n_registry) {
ast_log(LOG_ERROR, "Unhandled SCCP event, OPC=%d, DPC=%d, typ=%d\n", opc, dpc, typ);
}
}
void l4sccp_link_status_change(struct link* link, int up)
{
}
void l4isup_inservice(struct link* link)
{
if (!mtp_send_fifo)
mtp_send_fifo = mtp_get_send_fifo();
printf("l4isup_inservice link=%s\n", link->name);
}
void l4isup_event(struct mtp_event* event)
{
printf("l4isup_event\n");
struct isup_msg isup_msg;
int res;
res = decode_isup_msg(&isup_msg, event->buf, event->len);
if(!res) {
/* Q.764 (2.9.5): Discard invalid message.*/
ast_log(LOG_NOTICE, "ISUP decoding error, message discarded. (typ=%d)\n", isup_msg.typ);
} else {
int opc = isup_msg.opc;
int dpc = isup_msg.dpc;
int cic = isup_msg.cic;
int i, n;
struct linkset* linkset = event->isup.slink->linkset;
printf("ISUP event, OPC=%d, DPC=%d, CIC=%d, typ=%s\n", opc, dpc, cic, isupmsg(isup_msg.typ));
for (n = 0; n < n_registry; n++) {
if (registry[n].ss7_protocol == SS7_PROTO_ISUP) {
struct host* host = lookup_host_by_id(registry[n].host_ix);
for (i = 0; i < host->n_spans; i++) {
struct link* link = host->spans[i].link;
if (link->linkset == linkset) {
if ((link->first_cic <= cic) && (link->first_cic+32 > cic)) {
event->isup.slinkix = event->isup.slink->linkix;
mtp3_reply(registry[n].peerfd, (void*) event, sizeof(*event)+event->len, (const struct sockaddr*) ®istry[n].client, sizeof(registry[n].client));
return;
}
}
}
}
}
ast_log(LOG_ERROR, "Unhandled ISUP event, OPC=%d, DPC=%d, CIC=%d, typ=%s\n", opc, dpc, cic, isupmsg(isup_msg.typ));
}
}
void l4isup_link_status_change(struct link* link, int up)
{
printf("l4isup_link_status_change link=%s, up=%d\n", link->name, up);
link->linkset->inservice += (up*2-1);
if (up)
l4isup_inservice(link);
}
static void close_socket(int servsock, int* asockets, int* n_asockets, int p)
{
int i, j;
close(servsock);
for (i = p+1; i < *n_asockets; i++)
asockets[i-1] = asockets[i];
(*n_asockets)--;
for (i = 0; i < n_registry; i++) {
if (registry[i].peerfd == servsock) {
for (j = i+1; j < n_registry; j++)
registry[j-1] = registry[j];
n_registry--;
break;
}
}
}
static int setnonblock_fd(int s)
{
int res, flags;
res = fcntl(s, F_GETFL);
if(res < 0) {
ast_log(LOG_WARNING, "Could not obtain flags for socket fd: %s.\n", strerror(errno));
return -1;
}
flags = res | O_NONBLOCK;
res = fcntl(s, F_SETFL, flags);
if(res < 0) {
ast_log(LOG_WARNING, "Could not set socket fd non-blocking: %s.\n", strerror(errno));
return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -