📄 l4isup.c
字号:
isup_msg_add_variable(msg, sizeof(msg), &varptr, ¤t, ¶m[1], res); isup_msg_start_optional_part(msg, sizeof(msg), &varptr, ¤t); isup_msg_end_optional_part(msg, sizeof(msg), ¤t); mtp_enqueue_isup(pvt, msg, current); return 0;}static int isup_send_iam(struct ast_channel *chan, char *addr, char *rdni, char *dni, int dnilimit) { struct ss7_chan *pvt = chan->tech_pvt; unsigned char msg[MTP_MAX_PCK_SIZE]; unsigned char param[2 + PHONENUM_MAX]; int current, varptr; char dnicpy[100]; int pres_restr; int res; isup_msg_init(msg, sizeof(msg), this_host->opc, peerpc(pvt), pvt->cic, ISUP_IAM, ¤t); /* Nature of connection indicators Q.763 (3.35). */ param[0] = 0x00; /* No sattelite, no continuity check, no echo control */ isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 1); /* Forward call indicator Q.763 (3.23). */ param[0] = 0x60; /* No end-to-end method , no interworking, no end-to-end info, ISDN all the way, ISDN not required */ param[1] = 0x01; /* Originating access ISDN, no SCCP indication */ isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 2); /* Calling party's category Q.763 (3.11). */ param[0] = 0x0a; /* Ordinary calling subscriber */ isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 1); /* Transmission medium requirement Q.763 (3.54). */ param[0] = 0x00; /* Speech */ isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 1); /* Called party number Q.763 (3.9). */ isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 1, 1); if (dnilimit > 0 && strlen(dni) > dnilimit) { /* Make part of dni */ strncpy(dnicpy, dni, dnilimit); dnicpy[dnilimit] = '\0'; res = isup_called_party_num_encode_no_st(dnicpy, param, sizeof(param)); } else { res = isup_called_party_num_encode(dni, param, sizeof(param)); } if(res < 0) { ast_log(LOG_NOTICE, "Invalid format for phonenumber '%s'.\n", dni); request_hangup(chan, AST_CAUSE_INVALID_NUMBER_FORMAT); ast_mutex_unlock(&pvt->lock); return -1; } isup_msg_add_variable(msg, sizeof(msg), &varptr, ¤t, param, res); isup_msg_start_optional_part(msg, sizeof(msg), &varptr, ¤t); /* Calling partys number Q.763 (3.10). */ if((chan->cid.cid_pres & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED) { pres_restr = 1; } else { pres_restr = 0; } res = isup_calling_party_num_encode(chan->cid.cid_num, pres_restr, param, sizeof(param)); if(res < 0) { ast_log(LOG_DEBUG, "Invalid format for calling number, dropped.\n"); } else { isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_CALLING_PARTY_NUMBER, param, res); } if (*rdni) { /* ToDo: Pass on RDNIS (and redirection cause when we implement that) as ISUP parameters? */ /* Q.763 3.45 */ res = isup_calling_party_num_encode(rdni, pres_restr, param, sizeof(param)); isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_REDIRECTING_NUMBER, param, res); param[0] = 0x04; /* redirecting indicator: call diverted, all redirection information presentation restricted, original redirection reason: unknown */ param[1] = 0x31; /* reredicting counter: 1 redirection reason: unconditional */ isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_REDIRECTION_INFORMATION, param, 2); } /* End and send the message. */ isup_msg_end_optional_part(msg, sizeof(msg), ¤t); mtp_enqueue_isup(pvt, msg, current); ast_verbose(VERBOSE_PREFIX_3 "Sent IAM CIC=%-3d ANI=%s DNI=%s RNI=%s\n", pvt->cic, pres_restr ? "*****" : chan->cid.cid_num, dni, rdni); return 0;}/* Assume that we are called with chan->lock held (as ast_call() does). */static int ss7_call(struct ast_channel *chan, char *addr, int timeout) { struct ss7_chan *pvt = chan->tech_pvt; char *sep = strchr(addr, '/'); char rdni[100]; char dnicpy[100]; char dni[100]; int chunk_limit, chunk_sofar=0; int res; ast_mutex_lock(&pvt->lock); ast_log(LOG_DEBUG, "SS7 call, addr=%s, cid=%s(0x%x/%s) CIC=%d. linkset '%s'\n", (addr ? addr : "<NULL>"), (chan->cid.cid_num ? chan->cid.cid_num : "<NULL>"), chan->cid.cid_pres, ast_describe_caller_presentation(chan->cid.cid_pres), pvt->cic, pvt->link->linkset->name); pvt->addr = addr; pvt->attempts = 1; if (sep) addr = sep+1; strcpy(dni, addr); strcpy(rdni, chan->cid.cid_rdnis ? chan->cid.cid_rdnis : ""); sep = strchr(dni, ':'); if (sep) { *sep = '\0'; strcpy(rdni, sep+1); } chunk_limit = pvt->link->linkset->dni_chunk_limit; pvt->link->linkset->outgoing_calls++; res = isup_send_iam(chan, addr, rdni, dni, chunk_limit); if (res < 0) return res; if (chunk_limit > 0 && strlen(dni) > chunk_limit) { while(chunk_sofar < strlen(dni)) { strncpy(dnicpy, &dni[chunk_sofar], chunk_limit); chunk_sofar += chunk_limit; dnicpy[chunk_sofar] = '\0'; isup_send_sam(pvt, dnicpy, 1); } } pvt->state = ST_SENT_IAM; t7_start(chan); ast_mutex_unlock(&pvt->lock); return 0;}static int ss7_hangup(struct ast_channel *chan) { struct ss7_chan *pvt = chan->tech_pvt; if (!pvt || pvt->cic == -1) { decr_usecount(); ast_update_use_count(); return 0; } ast_verbose( VERBOSE_PREFIX_3 "SS7 hangup '%s' CIC=%d Cause=%d (state=%d)\n", chan->name, pvt->cic, chan->hangupcause, pvt->state); /* Digium insists that ss7_hangup() must be called with chan->lock() held, even though it is the wrong thing to do (bug 5051). So we have to unlock it on entry and re-lock it on exit to get sane locking semantics. */ ast_mutex_unlock(&chan->lock); /* First remove us from the global circuit list. */ lock_global(); ast_mutex_lock(&pvt->lock); decr_usecount(); ast_log(LOG_DEBUG, "SS7 hangup '%s' CIC=%d (state=%d), chan=0x%08lx\n", chan->name, pvt->cic, pvt->state, (unsigned long) chan); chan->tech_pvt = NULL; pvt->owner = NULL; /* Clear all the timers that may hold on to references to chan. This must be done while global lock is held to prevent races. */ t1_clear(pvt); t2_clear(pvt); t5_clear(pvt); t6_clear(pvt); t7_clear(pvt); t9_clear(pvt); t16_clear(pvt); t17_clear(pvt); t18_clear(pvt); t19_clear(pvt); t20_clear(pvt); t21_clear(pvt); t35_clear(pvt); if(pvt->state == ST_GOT_REL) { isup_send_rlc(pvt); ast_setstate(chan, AST_STATE_DOWN); free_cic(pvt); } else if(pvt->state == ST_SENT_REL) { t1_start(pvt); t5_start(pvt); } else if(pvt->state != ST_IDLE) { ast_log(LOG_DEBUG, "SS7 hangup '%s' CIC=%d cause=%d\n", chan->name, pvt->cic, chan->hangupcause); initiate_release_circuit(pvt, chan->hangupcause); } if (pvt->echocancel) { io_disable_echo_cancellation(pvt->zaptel_fd, pvt->cic); pvt->echocancel = 0; } ast_mutex_unlock(&pvt->lock); unlock_global(); ast_update_use_count(); ast_mutex_lock(&chan->lock); /* See above */ return 0;}static int ss7_answer(struct ast_channel *chan) { struct ss7_chan *pvt = chan->tech_pvt; unsigned char msg[MTP_MAX_PCK_SIZE]; int current, varptr; unsigned char param[2]; ast_mutex_lock(&pvt->lock); ast_log(LOG_DEBUG, "SS7 answer CIC=%d, pvt->state=%d.\n", pvt->cic, pvt->state); /* Send ANM instead of CON if previously sent ACM. */ if (pvt->state == ST_SENT_ACM) { isup_msg_init(msg, sizeof(msg), this_host->opc, peerpc(pvt), pvt->cic, ISUP_ANM, ¤t); param[0] = 0x14; /* Subscriber free, ordinary subscriber, no end-to-end */ param[1] = 0x14; /* No interworking, no end-to-end, ISDN all the way, no hold, terminating access ISDN, no echo control */ isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 0, 1); isup_msg_start_optional_part(msg, sizeof(msg), &varptr, ¤t); isup_msg_add_optional(msg, sizeof(msg), ¤t, IP_BACKWARD_CALL_INDICATORS, param, 2); isup_msg_end_optional_part(msg, sizeof(msg), ¤t); mtp_enqueue_isup(pvt, msg, current); } else if (pvt->state == ST_GOT_IAM) { isup_msg_init(msg, sizeof(msg), this_host->opc, peerpc(pvt), pvt->cic, ISUP_CON, ¤t); param[0] = 0x14; /* Subscriber free, ordinary subscriber, no end-to-end */ param[1] = 0x14; /* No interworking, no end-to-end, ISDN all the way, no hold, terminating access ISDN, no echo control */ isup_msg_add_fixed(msg, sizeof(msg), ¤t, param, 2); isup_msg_start_variable_part(msg, sizeof(msg), &varptr, ¤t, 0, 1); mtp_enqueue_isup(pvt, msg, current); } /* else: already connected */ pvt->state = ST_CONNECTED; ast_setstate(chan, AST_STATE_UP); /* Start echo-cancelling if required */ if (pvt->echocan_start) { if (!io_enable_echo_cancellation(pvt->zaptel_fd, pvt->cic, pvt->link->echocan_taps, pvt->link->echocan_train)) pvt->echocancel = 1; pvt->echocan_start = 0; } ast_mutex_unlock(&pvt->lock); return 0;}static void ss7_handle_event(struct ss7_chan *pvt, int event) { int res, doing_dtmf; switch(event) { case ZT_EVENT_DIALCOMPLETE: /* Chech if still doing DTMF sending. If not, set flag to start outputting audio again. */ res = ioctl(pvt->zaptel_fd, ZT_DIALING, &doing_dtmf); if(res < 0) { ast_log(LOG_WARNING, "Error querying zaptel for ZT_DIALING on cic=%d: %s.\n", pvt->cic, strerror(errno)); /* Better start the audio, don't want to permanently disable it. */ pvt->sending_dtmf = 0; } else if(!doing_dtmf) { /* Now we can start sending normal audio again. */ pvt->sending_dtmf = 0; } break; default: ast_log(LOG_NOTICE, "Unhandled zaptel event 0x%x on CIC=%d.\n", event, pvt->cic); }}static void get_zaptel_event(struct ss7_chan* pvt){ int res, event; /* While these should really be handled in ss7_exception(), they can also occur here, probably because of a race between the zaptel driver and the channel poll() loop. */ res = io_get_zaptel_event(pvt->zaptel_fd, &event); if(res < 0) { ast_mutex_unlock(&pvt->lock); ast_log(LOG_WARNING, "Error reading zaptel event for CIC=%d: %s.\n", pvt->cic, strerror(errno)); return; } else { ast_log(LOG_DEBUG, "Got event %d for CIC=%d, handling.\n", event, pvt->cic); ss7_handle_event(pvt, event); }}/* ast_read() calls us with chan->lock held, so we assume that this is always the case. */static struct ast_frame *ss7_read(struct ast_channel * chan) { struct ss7_chan *pvt = chan->tech_pvt; static struct ast_frame null_frame = { AST_FRAME_NULL }; struct ast_frame *processed_frame; int res, sofar; if (pvt->dohangup) { chan->hangupcause = pvt->dohangup; return NULL; } ast_mutex_lock(&pvt->lock); memset(&pvt->frame, 0, sizeof(pvt->frame)); pvt->frame.frametype = AST_FRAME_VOICE; pvt->frame.subclass = AST_FORMAT_ALAW; pvt->frame.datalen = AUDIO_READSIZE; pvt->frame.samples = AUDIO_READSIZE; pvt->frame.mallocd = 0; pvt->frame.offset = AST_FRIENDLY_OFFSET; pvt->frame.src = NULL; pvt->frame.data = &(pvt->buffer[AST_FRIENDLY_OFFSET]); memset(pvt->buffer, 0, sizeof(pvt->buffer)); sofar = 0; while(sofar < AUDIO_READSIZE) { res = read(pvt->zaptel_fd, &(pvt->buffer[AST_FRIENDLY_OFFSET + sofar]), AUDIO_READSIZE - sofar); if(res < 0) { if(errno == EINTR) { /* Interrupted syscall, try again. */ } else if(errno == EAGAIN || errno == EWOULDBLOCK) { static struct timeval lastreport = {0, 0}; static int supress = 0; struct timeval now; gettimeofday(&now, NULL); if (now.tv_sec - lastreport.tv_sec > 10) { ast_log(LOG_NOTICE, "Short read on CIC=%d (read only %d of %d) errno=%d (%s) (supressed %d).\n", pvt->cic, sofar, AUDIO_READSIZE, errno, strerror(errno), supress); lastreport = now; supress = 0; } else supress++; break; } else if(errno == ELAST) { struct pollfd fds[1]; get_zaptel_event(pvt); fds[0].fd = pvt->zaptel_fd; fds[0].events = POLLIN; /* we are trying to read data, wait up to 20 msec for next frame */ res = poll(fds, 1, 20); } else { ast_mutex_unlock(&pvt->lock); ast_log(LOG_WARNING, "Read error on CIC=%d: %s.\n", pvt->cic, strerror(errno)); return NULL; } } else if(res == 0) { ast_mutex_unlock(&pvt->lock); ast_log(LOG_WARNING, "EOF on zaptel device CIC=%d?!?\n", pvt->cic); return NULL; } else { sofar += res; } } if(sofar == 0) { ast_mutex_unlock(&pvt->lock); return &null_frame; }#ifndef xxxxx { int msecs = sofar / 8; struct timeval now; static struct timeval lastreport = {0, 0}; static int supress = 0; int tdiff;//xxx gettimeofday(&now, NULL); if (pvt->lastread.tv_sec) { tdiff = (now.tv_sec - pvt->lastread.tv_sec) * 1000000 + (now.tv_usec - pvt->lastread.tv_usec); if (tdiff/1000 > msecs + 100) { if (now.tv_sec - lastreport.tv_sec > 10) { ast_log(LOG_NOTICE, "Audio buffer underrun, data %d msecs, real time: %d msecs! (supressed %d)\n", msecs, tdiff / 1000, supress); lastreport = now; supress = 0; } else supress++; } } pvt->lastread = now; }#endif processed_frame = ast_dsp_process(chan, pvt->dsp, &pvt->frame); ast_mutex_unlock(&pvt->lock); return processed_frame;}static int ss7_write(struct ast_channel *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -