⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mtp3d.c

📁 asterisk1.4.6版本下 7#信令驱动 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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*) &registry[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*) &registry[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 + -