📄 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_ntoastatic int do_pid = 0;static struct lffifo **mtp_send_fifo;#define MAXCLIENTS 32int 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 *fh, struct mtp_event *event){ 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(&event->dump.stamp.tv_sec, sizeof(event->dump.stamp.tv_sec), 1, fh); fwrite(&usec, sizeof(usec), 1, fh); fwrite(&event->len, sizeof(event->len), 1, fh); fwrite(&event->len, sizeof(event->len), 1, fh); fwrite(event->buf, 1, event->len, fh); fflush(fh);}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 + -