?? pri.c
字號:
/* * libpri: An implementation of Primary Rate ISDN * * Written by Mark Spencer <markster@digium.com> * * Copyright (C) 2001-2005, Digium * All Rights Reserved. * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <unistd.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/select.h>#include <stdarg.h>#include "compat.h"#include "libpri.h"#include "pri_internal.h"#include "pri_facility.h"#include "pri_q921.h"#include "pri_q931.h"#include "pri_timers.h"char *pri_node2str(int node){ switch(node) { case PRI_UNKNOWN: return "Unknown node type"; case PRI_NETWORK: return "Network"; case PRI_CPE: return "CPE"; default: return "Invalid value"; }}char *pri_switch2str(int sw){ switch(sw) { case PRI_SWITCH_NI2: return "National ISDN"; case PRI_SWITCH_DMS100: return "Nortel DMS100"; case PRI_SWITCH_LUCENT5E: return "Lucent 5E"; case PRI_SWITCH_ATT4ESS: return "AT&T 4ESS"; case PRI_SWITCH_NI1: return "National ISDN 1"; case PRI_SWITCH_EUROISDN_E1: return "EuroISDN"; case PRI_SWITCH_GR303_EOC: return "GR303 EOC"; case PRI_SWITCH_GR303_TMC: return "GR303 TMC"; case PRI_SWITCH_QSIG: return "Q.SIG switch"; default: return "Unknown switchtype"; }}static void pri_default_timers(struct pri *pri, int switchtype){ int defaulttimers[20][PRI_MAX_TIMERS] = PRI_TIMERS_ALL; int x; for (x = 0; x<PRI_MAX_TIMERS; x++) { pri->timers[x] = defaulttimers[switchtype][x]; }}int pri_set_timer(struct pri *pri, int timer, int value){ if (timer < 0 || timer > PRI_MAX_TIMERS || value < 0) return -1; pri->timers[timer] = value; return 0;}int pri_get_timer(struct pri *pri, int timer){ if (timer < 0 || timer > PRI_MAX_TIMERS) return -1; return pri->timers[timer];}int pri_timer2idx(char *timer){ if (!strcasecmp(timer, "N200")) return PRI_TIMER_N200; else if (!strcasecmp(timer, "N201")) return PRI_TIMER_N201; else if (!strcasecmp(timer, "N202")) return PRI_TIMER_N202; else if (!strcasecmp(timer, "K")) return PRI_TIMER_K; else if (!strcasecmp(timer, "T200")) return PRI_TIMER_T200; else if (!strcasecmp(timer, "T202")) return PRI_TIMER_T202; else if (!strcasecmp(timer, "T203")) return PRI_TIMER_T203; else if (!strcasecmp(timer, "T300")) return PRI_TIMER_T300; else if (!strcasecmp(timer, "T301")) return PRI_TIMER_T301; else if (!strcasecmp(timer, "T302")) return PRI_TIMER_T302; else if (!strcasecmp(timer, "T303")) return PRI_TIMER_T303; else if (!strcasecmp(timer, "T304")) return PRI_TIMER_T304; else if (!strcasecmp(timer, "T305")) return PRI_TIMER_T305; else if (!strcasecmp(timer, "T306")) return PRI_TIMER_T306; else if (!strcasecmp(timer, "T307")) return PRI_TIMER_T307; else if (!strcasecmp(timer, "T308")) return PRI_TIMER_T308; else if (!strcasecmp(timer, "T309")) return PRI_TIMER_T309; else if (!strcasecmp(timer, "T310")) return PRI_TIMER_T310; else if (!strcasecmp(timer, "T313")) return PRI_TIMER_T313; else if (!strcasecmp(timer, "T314")) return PRI_TIMER_T314; else if (!strcasecmp(timer, "T316")) return PRI_TIMER_T316; else if (!strcasecmp(timer, "T317")) return PRI_TIMER_T317; else if (!strcasecmp(timer, "T318")) return PRI_TIMER_T318; else if (!strcasecmp(timer, "T319")) return PRI_TIMER_T319; else if (!strcasecmp(timer, "T320")) return PRI_TIMER_T320; else if (!strcasecmp(timer, "T321")) return PRI_TIMER_T321; else if (!strcasecmp(timer, "T322")) return PRI_TIMER_T322; else return -1;}static int __pri_read(struct pri *pri, void *buf, int buflen){ int res = read(pri->fd, buf, buflen); if (res < 0) { if (errno != EAGAIN) pri_error(pri, "Read on %d failed: %s\n", pri->fd, strerror(errno)); return 0; } return res;}static int __pri_write(struct pri *pri, void *buf, int buflen){ int res = write(pri->fd, buf, buflen); if (res < 0) { if (errno != EAGAIN) pri_error(pri, "Write to %d failed: %s\n", pri->fd, strerror(errno)); return 0; } return res;}static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata){ struct pri *p; p = malloc(sizeof(struct pri)); if (p) { memset(p, 0, sizeof(struct pri)); p->fd = fd; p->read_func = rd; p->write_func = wr; p->userdata = userdata; p->localtype = node; p->switchtype = switchtype; p->cref = 1; p->sapi = Q921_SAPI_CALL_CTRL; p->tei = 0; p->nsf = PRI_NSF_NONE; p->protodisc = Q931_PROTOCOL_DISCRIMINATOR; p->master = master; p->callpool = &p->localpool; pri_default_timers(p, switchtype);#ifdef LIBPRI_COUNTERS p->q921_rxcount = 0; p->q921_txcount = 0; p->q931_rxcount = 0; p->q931_txcount = 0;#endif if (switchtype == PRI_SWITCH_GR303_EOC) { p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; p->sapi = Q921_SAPI_GR303_EOC; p->tei = Q921_TEI_GR303_EOC_OPS; p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_EOC_PATH, p, NULL, NULL, NULL); if (!p->subchannel) { free(p); p = NULL; } } else if (switchtype == PRI_SWITCH_GR303_TMC) { p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; p->sapi = Q921_SAPI_GR303_TMC_CALLPROC; p->tei = Q921_TEI_GR303_TMC_CALLPROC; p->subchannel = __pri_new(-1, node, PRI_SWITCH_GR303_TMC_SWITCHING, p, NULL, NULL, NULL); if (!p->subchannel) { free(p); p = NULL; } } else if (switchtype == PRI_SWITCH_GR303_TMC_SWITCHING) { p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; p->sapi = Q921_SAPI_GR303_TMC_SWITCHING; p->tei = Q921_TEI_GR303_TMC_SWITCHING; } else if (switchtype == PRI_SWITCH_GR303_EOC_PATH) { p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; p->sapi = Q921_SAPI_GR303_EOC; p->tei = Q921_TEI_GR303_EOC_PATH; } /* Start Q.921 layer, Wait if we're the network */ if (p) q921_start(p, p->localtype == PRI_CPE); } return p;}void pri_call_set_useruser(q931_call *c, const char *userchars){ if (userchars) libpri_copy_string(c->useruserinfo, userchars, sizeof(c->useruserinfo));}void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars){ sr->useruserinfo = userchars;}int pri_restart(struct pri *pri){ /* Restart Q.921 layer */ if (pri) { q921_reset(pri); q921_start(pri, pri->localtype == PRI_CPE); } return 0;}struct pri *pri_new(int fd, int nodetype, int switchtype){ return __pri_new(fd, nodetype, switchtype, NULL, __pri_read, __pri_write, NULL);}struct pri *pri_new_cb(int fd, int nodetype, int switchtype, pri_io_cb io_read, pri_io_cb io_write, void *userdata){ if (!io_read) io_read = __pri_read; if (!io_write) io_write = __pri_write; return __pri_new(fd, nodetype, switchtype, NULL, io_read, io_write, userdata);}void *pri_get_userdata(struct pri *pri){ return pri ? pri->userdata : NULL;}void pri_set_userdata(struct pri *pri, void *userdata){ if (pri) pri->userdata = userdata;}void pri_set_nsf(struct pri *pri, int nsf){ if (pri) pri->nsf = nsf;}char *pri_event2str(int id){ switch(id) { case PRI_EVENT_DCHAN_UP: return "D-Channel Up"; case PRI_EVENT_DCHAN_DOWN: return "D-channel Down"; case PRI_EVENT_RESTART: return "Restart channel"; case PRI_EVENT_RING: return "Ring"; case PRI_EVENT_HANGUP: return "Hangup"; case PRI_EVENT_RINGING: return "Ringing"; case PRI_EVENT_ANSWER: return "Answer"; case PRI_EVENT_HANGUP_ACK: return "Hangup ACK"; case PRI_EVENT_RESTART_ACK: return "Restart ACK"; case PRI_EVENT_FACNAME: return "FacName"; case PRI_EVENT_INFO_RECEIVED: return "Info Received"; case PRI_EVENT_PROCEEDING: return "Proceeding"; case PRI_EVENT_SETUP_ACK: return "Setup ACK"; case PRI_EVENT_HANGUP_REQ: return "Hangup Req"; case PRI_EVENT_NOTIFY: return "Notify"; case PRI_EVENT_PROGRESS: return "Progress"; case PRI_EVENT_CONFIG_ERR: return "Configuration Error"; default: return "Unknown Event"; }}pri_event *pri_check_event(struct pri *pri){ char buf[1024]; int res; pri_event *e; res = pri->read_func ? pri->read_func(pri, buf, sizeof(buf)) : 0; if (!res) return NULL; /* Receive the q921 packet */ e = q921_receive(pri, (q921_h *)buf, res); return e;}static int wait_pri(struct pri *pri){ struct timeval *tv, real; fd_set fds; int res; FD_ZERO(&fds); FD_SET(pri->fd, &fds); tv = pri_schedule_next(pri); if (tv) { gettimeofday(&real, NULL); real.tv_sec = tv->tv_sec - real.tv_sec; real.tv_usec = tv->tv_usec - real.tv_usec; if (real.tv_usec < 0) { real.tv_usec += 1000000; real.tv_sec -= 1; } if (real.tv_sec < 0) { real.tv_sec = 0; real.tv_usec = 0; } } res = select(pri->fd + 1, &fds, NULL, NULL, tv ? &real : tv); if (res < 0) return -1; return res;}pri_event *pri_mkerror(struct pri *pri, char *errstr){ /* Return a configuration error */ pri->ev.err.e = PRI_EVENT_CONFIG_ERR; libpri_copy_string(pri->ev.err.err, errstr, sizeof(pri->ev.err.err)); return &pri->ev;}pri_event *pri_dchannel_run(struct pri *pri, int block){ pri_event *e; int res; if (!pri) return NULL; if (block) { do { e = NULL; res = wait_pri(pri); /* Check for error / interruption */ if (res < 0) return NULL; if (!res) e = pri_schedule_run(pri); else e = pri_check_event(pri); } while(!e); } else { e = pri_check_event(pri); return e; } return e;}void pri_set_debug(struct pri *pri, int debug){ if (!pri) return; pri->debug = debug; if (pri->subchannel) pri_set_debug(pri->subchannel, debug);}int pri_get_debug(struct pri *pri){ if (!pri) return -1; if (pri->subchannel)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -