?? pri.c
字號:
/* * libpri: An implementation of Primary Rate ISDN * * Written by Mark Spencer <markster@linux-suppot.net> * * This program is confidential * * Copyright (C) 2001, Linux Support Services, Inc. * All Rights Reserved. * */#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 "libpri.h"#include "pri_internal.h"#include "pri_q921.h"#include "pri_q931.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"; default: return "Unknown switchtype"; }}static struct pri *__pri_new(int fd, int node, int switchtype, struct pri *master){ struct pri *p; p = malloc(sizeof(struct pri)); if (p) { memset(p, 0, sizeof(struct pri)); p->fd = fd; 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;#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); 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); 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;}struct pri *pri_new(int fd, int node, int switchtype){ return __pri_new(fd, node, switchtype, NULL);}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_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 = read(pri->fd, buf, sizeof(buf)); if (res < 0) { if (errno != EAGAIN) pri_error("Read on %d failed: %s\n", pri->fd, strerror(errno)); return NULL; } 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; strncpy(pri->ev.err.err, errstr, sizeof(pri->ev.err.err) - 1); 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_acknowledge(struct pri *pri, q931_call *call, int channel, int info){ if (!pri || !call) return -1; return q931_alerting(pri, call, channel, info);}int pri_proceeding(struct pri *pri, q931_call *call, int channel, int info){ if (!pri || !call) return -1; return q931_call_proceeding(pri, call, channel, info);}int pri_progress(struct pri *pri, q931_call *call, int channel, int info){ if (!pri || !call) return -1; return q931_call_progress(pri, call, channel, info);}int pri_information(struct pri *pri, q931_call *call, char digit){ if (!pri || !call) return -1; return q931_information(pri, call, digit);}int pri_notify(struct pri *pri, q931_call *call, int channel, int info){ if (!pri || !call) return -1; return q931_notify(pri, call, channel, info);}void pri_destroycall(struct pri *pri, q931_call *call){ if (pri && call) __q931_destroycall(pri, call); return;}int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn){ if (!pri || !call) return -1; return q931_setup_ack(pri, call, channel, nonisdn);}int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn){ if (!pri || !call) return -1; return q931_connect(pri, call, channel, nonisdn);}#if 0/* deprecated routines, use pri_hangup */int pri_release(struct pri *pri, q931_call *call, int cause){ if (!pri || !call) return -1; return q931_release(pri, call, cause);}int pri_disconnect(struct pri *pri, q931_call *call, int cause){ if (!pri || !call) return -1; return q931_disconnect(pri, call, cause);}#endifint pri_hangup(struct pri *pri, q931_call *call, int cause){ if (!pri || !call) return -1; if (cause == -1) /* normal clear cause */ cause = 16; return q931_hangup(pri, call, cause);}int pri_reset(struct pri *pri, int channel){ if (!pri) return -1; return q931_restart(pri, channel);}q931_call *pri_new_call(struct pri *pri){ if (!pri) return NULL; return q931_new_call(pri);}void pri_dump_event(struct pri *pri, pri_event *e){ if (!pri || !e) return; pri_message("Event type: %s (%d)\n", pri_event2str(e->gen.e), e->gen.e); switch(e->gen.e) { case PRI_EVENT_DCHAN_UP: case PRI_EVENT_DCHAN_DOWN: break; case PRI_EVENT_CONFIG_ERR: pri_message("Error: %s", e->err.err); break; case PRI_EVENT_RESTART: pri_message("Restart on channel %d\n", e->restart.channel); case PRI_EVENT_RING: pri_message("Calling number: %s (%s, %s)\n", e->ring.callingnum, pri_plan2str(e->ring.callingplan), pri_pres2str(e->ring.callingpres)); pri_message("Called number: %s (%s)\n", e->ring.callednum, pri_plan2str(e->ring.calledplan)); pri_message("Channel: %d (%s) Reference number: %d\n", e->ring.channel, e->ring.flexible ? "Flexible" : "Not Flexible", e->ring.cref); break; case PRI_EVENT_HANGUP: pri_message("Hangup, reference number: %d, reason: %s\n", e->hangup.cref, pri_cause2str(e->hangup.cause)); break; default: pri_message("Don't know how to dump events of type %d\n", e->gen.e); }}static void pri_sr_init(struct pri_sr *req){ memset(req, 0, sizeof(struct pri_sr)); }int pri_setup(struct pri *pri, q931_call *c, struct pri_sr *req){ if (!pri || !c) return -1; return q931_setup(pri, c, req);}int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan,int ulayer1){ struct pri_sr req; if (!pri || !c) return -1; pri_sr_init(&req); req.transmode = transmode; req.channel = channel; req.exclusive = exclusive; req.nonisdn = nonisdn; req.caller = caller; req.callerplan = callerplan; req.callername = callername; req.callerpres = callerpres; req.called = called; req.calledplan = calledplan; req.userl1 = ulayer1; return q931_setup(pri, c, &req);} static void (*__pri_error)(char *stuff);static void (*__pri_message)(char *stuff);void pri_set_message(void (*func)(char *stuff)){ __pri_message = func;}void pri_set_error(void (*func)(char *stuff)){ __pri_error = func;}void pri_message(char *fmt, ...){ char tmp[1024]; va_list ap; va_start(ap, fmt); vsnprintf(tmp, sizeof(tmp), fmt, ap); va_end(ap); if (__pri_message) __pri_message(tmp); else fputs(tmp, stdout);}void pri_error(char *fmt, ...){ char tmp[1024]; va_list ap; va_start(ap, fmt); vsnprintf(tmp, sizeof(tmp), fmt, ap); va_end(ap); if (__pri_error) __pri_error(tmp); else fputs(tmp, stderr);}/* Set overlap mode */void pri_set_overlapdial(struct pri *pri,int state){ pri->overlapdial = state;}int pri_fd(struct pri *pri){ return pri->fd;}char *pri_dump_info_str(struct pri *pri){ char buf[4096]; int len = 0;#ifdef LIBPRI_COUNTERS struct q921_frame *f; int q921outstanding = 0;#endif if (!pri) return NULL; /* Might be nice to format these a little better */ len += sprintf(buf + len, "Switchtype: %s\n", pri_switch2str(pri->switchtype)); len += sprintf(buf + len, "Type: %s\n", pri_node2str(pri->localtype));#ifdef LIBPRI_COUNTERS /* Remember that Q921 Counters include Q931 packets (and any retransmissions) */ len += sprintf(buf + len, "Q931 RX: %d\n", pri->q931_rxcount); len += sprintf(buf + len, "Q931 TX: %d\n", pri->q931_txcount); len += sprintf(buf + len, "Q921 RX: %d\n", pri->q921_rxcount); len += sprintf(buf + len, "Q921 TX: %d\n", pri->q921_txcount); f = pri->txqueue; while (f) { q921outstanding++; f = f->next; } len += sprintf(buf + len, "Q921 Outstanding: %d\n", q921outstanding);#endif len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen, pri->window); len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej); len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit); len += sprintf(buf + len, "Retrans: %d\n", pri->retrans); len += sprintf(buf + len, "Busy: %d\n", pri->busy); len += sprintf(buf + len, "Overlap Dial: %d\n", pri->overlapdial); return strdup(buf);}int pri_get_crv(struct pri *pri, q931_call *call, int *callmode){ return q931_call_getcrv(pri, call, callmode);}int pri_set_crv(struct pri *pri, q931_call *call, int crv, int callmode){ return q931_call_setcrv(pri, call, crv, callmode);}void pri_enslave(struct pri *master, struct pri *slave){ if (master && slave) slave->callpool = &master->localpool;}struct pri_sr *pri_sr_new(void){ struct pri_sr *req; req = malloc(sizeof(struct pri_sr)); if (req) pri_sr_init(req); return req;}void pri_sr_free(struct pri_sr *sr){ free(sr);}int pri_sr_set_channel(struct pri_sr *sr, int channel, int exclusive, int nonisdn){ sr->channel = channel; sr->exclusive = exclusive; sr->nonisdn = nonisdn; return 0;}int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1){ sr->transmode = transmode; sr->userl1 = userl1; return 0;}int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int numcomplete){ sr->called = called; sr->calledplan = calledplan; sr->numcomplete = numcomplete; return 0;}int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres){ sr->caller = caller; sr->callername = callername; sr->callerplan = callerplan; sr->callerpres = callerpres; return 0;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -