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

📄 mtp.c

📁 asterisk1.4.6版本下 7#信令驱动 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* mtp.c - MTP2 and MTP3 functionality.
 *
 * Copyright (C) 2005-2006, Sifira A/S.
 *
 * Author: Kristian Nielsen <kn@sifira.dk>
 *         Anders Baekgaard <ab@sifira.dk>
 *         Anders Baekgaard <ab@dicea.dk>
 *
 * 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 <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include "zaptel.h"
#define FAST_HDLC_NEED_TABLES
#include "fasthdlc.h"

#include "config.h"
#include "mtp.h"
#include "transport.h"
#include "lffifo.h"
#include "cluster.h"
#include "utils.h"

#ifdef MTP_STANDALONE
#include "aststubs.h"
#define cluster_mtp_received(link, event) {}
#define cluster_mtp_forward(req) {}
#define cluster_receivers_alive(linkset) (0)
#else
#include "asterisk/options.h"
#include "asterisk/logger.h"
#include "asterisk/sched.h"
#define mtp_sched_add ast_sched_add
#define mtp_sched_del ast_sched_del
#define mtp_sched_runq ast_sched_runq
#define mtp_sched_context_create sched_context_create
#define mtp_sched_context_destroy sched_context_destroy
#endif

/* NOTE: most of this code is run in the MTP thread, and has realtime
   constraints because of the need to constantly feed/read the
   signalling link with low latence and no frame drop.

   The thread runs with high realtime priority, and any kind of
   locking should generally be avoided. This includes ast_log() (use
   fifo_log() instead), and malloc()/free()!
*/


/* For testing failover mechanism */
int testfailover = 0;

/* #define DROP_PACKETS_PCT 66 */
/* #define DO_RAW_DUMPS */

/* Scheduling context for MTP2. */
/* This should ONLY be used by the MTP2 thread, otherwise the locking done
   by the sched operations may fatally delay the MTP2 thread because of
   priority inversion. */
static struct sched_context *mtp2_sched = NULL;

/* Set true to ask mtp thread to stop */
static int stop_mtp_thread;
static int receivepipe[2] = {-1, -1};
/* Lock-free FIFOs for communication with the MTP thread.
   The sendbuf is polled by the MTP thread whenever the link is ready to
   transmit data (every 2msec). It contains struct mtp_req entries for
   the higher level protocol layers (currently only ISUP).
   The receivebuf has an associated event pipe, and the MTP thread do
   non-blocking dummy writes to it whenever blocks are put in the buffer.
   The SS7 monitor thread can then wait for new data in poll(). The
   receivebuf contains struct mtp_event entries.
   The controlbuf is polled by the MTP thread, it contains struct mtp_req
   entries for control purposes only.
 */
struct lffifo *sendbuf[MAX_LINKSETS];
struct lffifo *receivebuf;
struct lffifo *controlbuf;


typedef struct mtp2_state {

  /* MTP2 stuff. */

  enum {
    /* Link is stopped by management command, will not go up until
       started explicitly. */
    MTP2_DOWN,
    /* Initial alignment has started, link is transmitting 'O', but no 'O',
       'N', or 'E' has been received. */
    MTP2_NOT_ALIGNED,
    /* 'O' has been received, 'N' or 'E' is transmitted. */
    MTP2_ALIGNED,
    /* 'N' or 'E' is transmitted and received. Runs for the duration of T4 to
       check that the link is of sufficient quality in terms of error rate. */
    MTP2_PROVING,
    /* Local T4 expired, and we are sending FISU, but remote is still
       proving. */
    MTP2_READY,
    /* The link is active sending and receiving FISU and MSU. */
    MTP2_INSERVICE,
  } state;

  /* Counts of raw bytes read and written, used to timestamp raw dumps.
     Make them double to avoid overflow for quite a while. */
  double readcount, writecount;

  /* Sequence numbers and indicator bits to be sent in signalling units. */
  int send_fib;
  int send_bsn, send_bib;

  /* Send initial SLTM? */
  int send_sltm;

  /* Timeslot for signalling channel */
  int schannel;
  int slinkno;
  struct link* link;
  int sls;
  int subservice;
  /* logical link name */
  char* name;
  /* Open fd for signalling link zaptel device. */
  int fd;

  /* Receive buffer. */
  unsigned char rx_buf[272 + 7];
  int rx_len;
  unsigned short rx_crc;

  /* Transmit buffer. */
  unsigned char tx_buffer[272 + 7 + 5];
  int tx_len;
  int tx_sofar;
  int tx_do_crc;                /* Flag used to handle writing CRC bytes */
  unsigned short tx_crc;

  /* Zaptel transmit buffer. */
  unsigned char zap_buf[ZAP_BUF_SIZE];
  int zap_buf_full;

  /* HDLC encoding and decoding state. */
  struct fasthdlc_state h_rx;
  struct fasthdlc_state h_tx;

  /* Last few raw bytes received, for debugging link errors. */
  unsigned char backbuf[36];
  int backbuf_idx;

  /* Retransmit buffer. */
  struct { int len; unsigned char buf[MTP_MAX_PCK_SIZE]; } retrans_buf[128];
  /* Retransmit counter; if this is != -1, it means that retransmission is
     taking place, with this being the next sequence number to retransmit. */
  int retrans_seq;
  /* Last sequence number ACK'ed by peer. */
  int retrans_last_acked;
  /* Last sequence number sent to peer. */
  int retrans_last_sent;
  /* Counter for signal unit/alignment error rate monitors (Q.703 (10)). */
  int error_rate_mon;
  /* Counters matching the D and N values of the error rate monitors. */
  int emon_ncount, emon_dcount;
  /* Counter for bad BSN */
  int bsn_errors;
  /* Q.703 timer T1 "alignment ready" (waiting for peer to end initial
     alignment after we are done). */
  int mtp2_t1;
  /* Q.703 timer T2 "not aligned" (waiting to receive O, E, or N after sending
     O). */
  int mtp2_t2;
  /* Q.703 timer T3 "aligned" (waiting to receive E or N after sending E or
     N). */
  int mtp2_t3;
  /* Q.703 timer T4 "proving period" - proving time before ending own initial
     alignment. */
  int mtp2_t4;
  /* Q.703 timer T7 "excessive delay of acknowledgement" . */
  int mtp2_t7;

  /* Set true when SLTA is received and User Parts (ie. ISUP) is notified that
     the link is now in service. */
  int level4_up;

  /* Hm, the rest is actually MTP3 state. Move to other structure, or
     rename this structure. */
  int sltm_t1;                  /* Timer T1 for SLTM (Q.707) */
  int sltm_t2;                  /* Timer T2 for SLTM (Q.707) */
  int sltm_tries;               /* For SLTM retry (Q.707 (2.2)) */

  /* Q.704 timer T17, "initial alignment restart delay". */
  int mtp3_t17;
} mtp2_t;

/* ToDo: Support more than one signalling link ... */
/* ToDo: Need real initialization, that doesn't depend on linker. */
mtp2_t mtp2_state[MAX_SCHANNELS];


/* Get the next sequence number, modulo 128. */
#define MTP_NEXT_SEQ(x) (((x) + 1) % 128)

/* Forward declaration, needed because of cyclic reference graph. */
static mtp2_t* find_alternative_slink(mtp2_t* m);
static void start_initial_alignment(mtp2_t *m, char* reason);
static void abort_initial_alignment(mtp2_t *m);
static void mtp2_cleanup(mtp2_t *m);
static void mtp2_queue_msu(mtp2_t *m, int sio, unsigned char *sif, int len);
static void deliver_l4(mtp2_t *m, unsigned char *sif, int len, int sio);
static void l4up(mtp2_t* m);
static void l4down(mtp2_t* m);
static void t7_stop(mtp2_t *m);
static void fifo_log(mtp2_t *m, int level, const char *file, int line,
		     const char *function, const char *format, ...)
     __attribute__ ((format (printf, 6, 7)));
static void process_msu(struct mtp2_state* m, unsigned char* buf, int len);

static inline ss7_variant variant(mtp2_t* m)   /* by lin.miao@openvox.cn */
{
  return m->link->linkset->variant;
}

int mtp2_slink_inservice(int ix) {
  struct mtp2_state* m = &mtp2_state[ix];
  return m->state == MTP2_INSERVICE;
}

int mtp_cmd_linkstatus(char* buff, int slinkno)
{
  char* format = "linkset %s, link %s, schannel %d, sls %d, %s, rx: %d, tx: %d/%d, sentseq/lastack: %d/%d, total %9llu, %9llu\n";

  char* s = "?";
  if (slinkno >= this_host->n_schannels)
    return -1;
  /* Todo: when more than one signalling link supported, check against that */
  struct mtp2_state* m = &mtp2_state[slinkno];
  switch (m->state) {
  case MTP2_DOWN: s = "DOWN"; break;
  case MTP2_NOT_ALIGNED: s = "NOT_ALIGNED"; break;
  case MTP2_ALIGNED: s = "ALIGNED"; break;
  case MTP2_PROVING: s = "PROVING"; break;
  case MTP2_READY: s = "READY"; break;
  case MTP2_INSERVICE: s = "INSERVICE"; break;
  default: s = "UNKNOWN";
  }
  sprintf(buff, format, m->link->linkset->name, m->link->name, m->schannel, m->sls, s, m->rx_len, m->tx_sofar, m->tx_len, m->retrans_last_sent, m->retrans_last_acked, (long long) m->readcount, (long long) m->writecount);
  return 0;
}

int mtp_cmd_data(int fd, int argc, char *argv[])
{
  unsigned char buf[MTP_EVENT_MAX_SIZE];
  int len = 0;
  int i;
  mtp2_t* m = &mtp2_state[0];

  for (i = 3; i < argc; i++) {
    char* p = argv[i];
    while (*p) {
      char b[3];
      unsigned int v;
      if (*p == ' ') {
	p++;
	continue;
      }
      b[0] = *p++;
      b[1] = *p++;
      b[2] = 0;
      sscanf(b, "%x", &v);
      buf[len++] = v;
    }
  }
  mtp2_queue_msu(m, 3, buf, len);
  deliver_l4(m, &buf[0], len, MTP_EVENT_SCCP);
  return 0;
}


static inline int peerpc(mtp2_t* m)
{
  return m->link->linkset->dpc;
}


static inline int linkpeerpc(mtp2_t* m)
{
  if (m->link->dpc)
    return m->link->dpc;
  return m->link->linkset->dpc;
}


static mtp2_t* findtargetslink(mtp2_t *originalm, int sls)
{
  int i;
  struct link* link = originalm->link;
  struct mtp2_state* bestm = NULL;

  for (i = 0; i < this_host->n_schannels; i++) {
    struct mtp2_state* m = &mtp2_state[i];
    struct link* slink = m->link;
    if (m->sls == sls) {
      if (link->linkset == slink->linkset) {
	fifo_log(m, LOG_DEBUG, "Target slink %s %d -> %s\n", originalm->name, sls, m->name);
        return m;
      }
      if (is_combined_linkset(link->linkset, slink->linkset))
        bestm = m;
    }
  }
  fifo_log(originalm, LOG_DEBUG, "Target slink %s %d -> %s\n", originalm->name, sls, bestm ? bestm->name : "(none)");
  return bestm;
}


static void mtp_put(mtp2_t *m, struct mtp_event *event) {
  static int log_safe_count = 0;
  int res;

  res = lffifo_put(receivebuf, (unsigned char *)event,
                   sizeof(*event) + event->len);
  if(res) {
    /* Can't fifo_log() here, or we would get an infinite loop. */
    /* Still, avoid excessive logging if the other thread gets long behind. */
    if(log_safe_count == 0) {
      ast_log(LOG_NOTICE, "Full MTP receivebuf, event lost, type=%d.\n", event->typ);
      log_safe_count = 2000;
    }
  } else {
    /* Wake up the other end. */
    write(receivepipe[1], "\0", 1);
  }
  if ((event->typ == MTP_EVENT_ISUP) || (event->typ == MTP_EVENT_STATUS)) {
    cluster_mtp_received(m ? m->link : NULL, event);
  }

  if(log_safe_count > 0) {
    log_safe_count--;
  }
}

/* Use this instead of ast_log() in the MTP thread, to avoid locking
   issues interupting the link timing.
   Note that LOG_WHATEVER includes all of (level, file, line, function), thanks
   to #define trickery in asterisk/logger.h! */

/* Grmble... stupid GCC allows the __attribute__ only in a
   declaration, not definition. */
static void fifo_log(mtp2_t *m, int level, const char *file, int line,
		     const char *function, const char *format, ...)
{
  va_list arg;
  unsigned char buf[MTP_EVENT_MAX_SIZE];
  struct mtp_event *event = (struct mtp_event *)buf;

  event->typ = MTP_EVENT_LOG;
  event->log.level = level;
  event->log.file = file;
  event->log.line = line;
  event->log.function = function;
  va_start(arg, format);
  vsnprintf((char*)event->buf, sizeof(buf) - sizeof(struct mtp_event), format, arg);
  va_end(arg);
  event->len = strlen((char*)event->buf) + 1;
  mtp_put(m, event);
}

static void log_frame(mtp2_t *m, int out, unsigned char *buf, int len) {
  unsigned char ebuf[MTP_EVENT_MAX_SIZE];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -