📄 iax.c
字号:
session->transfer.sin_family = AF_INET; session->transfercallno = atoi(s); free(s); session->transferring = TRANSFER_BEGIN; e->etype = IAX_EVENT_TXREPLY; iax_do_event(session, e); } } } } free(e); return NULL; case IAX_COMMAND_DPREP: /* Received dialplan reply */ printf("Got dialplan reply: %s\n", text); e->etype = IAX_EVENT_DPREP; s = extract(text, "number="); if (s) e->event.dprep.number = s; e->event.dprep.canexist = 0; e->event.dprep.exists = 0; e->event.dprep.nonexistant = 0; s = extract(text, "status="); if (s) { if (!strcmp(s, "canexist")) e->event.dprep.canexist = 1; else if (!strcmp(s, "exists")) e->event.dprep.exists = 1; else if (!strcmp(s, "nonexistant")) e->event.dprep.nonexistant = 1; else fprintf(stderr, "Unknown status '%s'\n", s); free(s); } e->event.dprep.ignorepat = 0; s = extract(text, "ignorepat="); if (s) { if (!strcmp(s, "yes")) e->event.dprep.ignorepat = 1; free(s); } s = extract(text, "expirey="); if (s) { e->event.dprep.expirey = atoi(s); if (e->event.dprep.expirey < 0) e->event.dprep.expirey = 0; free(s); } else e->event.dprep.expirey = 0; /* Return immediately, makes no sense to schedule */ return e; case IAX_COMMAND_TXCNT: /* Received a transfer connect. Accept it if we're transferring */ e->etype = IAX_EVENT_TXACCEPT; if (session->transferring) iax_do_event(session, e); free(e); return NULL; case IAX_COMMAND_TXACC: e->etype = IAX_EVENT_TXREADY; if (session->transferring) { /* Cancel any more connect requests */ sch = schedq; while(sch) { if (sch->frame && sch->frame->transferpacket) sch->frame->retries = -1; sch = sch->next; } session->transferring = TRANSFER_READY; iax_do_event(session, e); } free(e); return NULL; case IAX_COMMAND_TXREL: printf("Release: text is %s\n", text); /* Release the transfer */ s = extract(text, "peercallno="); if (s) session->peercallno = atoi(s); /* Change from transfer to session now */ memcpy(&session->peeraddr, &session->transfer, sizeof(session->peeraddr)); memset(&session->transfer, 0, sizeof(session->transfer)); session->transferring = TRANSFER_NONE; /* Force retransmission of a real voice packet, and reset all timing */ session->svoiceformat = -1; session->voiceformat = 0; memset(&session->rxcore, 0, sizeof(session->rxcore)); memset(&session->offset, 0, sizeof(session->offset)); memset(&session->history, 0, sizeof(session->history)); session->jitterbuffer = 0; session->jitter = 0; session->lag = 0; /* Reset sequence numbers */ session->oseqno = 0; session->iseqno = 0; session->lastsent = 0; session->last_ts = 0; session->lastvoicets = 0; session->pingtime = 30; e->etype = IAX_EVENT_TRANSFER; e->event.transfer.newip = strdup(inet_ntoa(session->peeraddr.sin_addr)); e->event.transfer.newport = ntohs(session->peeraddr.sin_port); /* We have to dump anything we were going to (re)transmit now that we've been transferred since they're all invalid and for the old host. */ sch = schedq; while(sch) { if (sch->frame && (sch->frame->session == session)) sch->frame->retries = -1; sch = sch->next; } return e; case IAX_COMMAND_QUELCH: e->etype = IAX_EVENT_QUELCH; session->quelch = 1; return e; case IAX_COMMAND_UNQUELCH: e->etype = IAX_EVENT_UNQUELCH; session->quelch = 0; return e; default: DEBU(G "Don't know what to do with IAX command %d\n", subclass); free(e); return NULL; } break; case AST_FRAME_CONTROL: switch(subclass) { case AST_CONTROL_ANSWER: e->etype = IAX_EVENT_ANSWER; return schedule_delivery(e, ts); case AST_CONTROL_BUSY: e->etype = IAX_EVENT_BUSY; return schedule_delivery(e, ts); case AST_CONTROL_RINGING: e->etype = IAX_EVENT_RINGA; return schedule_delivery(e, ts); default: DEBU(G "Don't know what to do with AST control %d\n", subclass); free(e); return NULL; } break; case AST_FRAME_IMAGE: e->etype = IAX_EVENT_IMAGE; e->event.image.format = subclass; if (datalen) { e->event.image.data = (char *)malloc(datalen); e->event.image.datalen = datalen; if (e->event.image.data) { memcpy(e->event.image.data, fh->data, datalen); } else { free(e); e = NULL; DEBU(G "Out of memory\n"); return NULL; } } else { /* Empty image frame? Maybe it could happen... */ e->event.image.data = NULL; e->event.image.datalen = 0; } return schedule_delivery(e, ts); case AST_FRAME_TEXT: e->etype = IAX_EVENT_TEXT; strncpy(e->event.text.text, (char *)fh->data, datalen); return schedule_delivery(e, ts); case AST_FRAME_HTML: switch(fh->csub) { case AST_HTML_LINKURL: e->event.url.link = 1; /* Fall through */ case AST_HTML_URL: e->etype = IAX_EVENT_URL; if (datalen) { e->event.url.url = (char *)malloc(datalen + 1); strncpy(e->event.url.url, (char *)fh->data, datalen); } return schedule_delivery(e, ts); case AST_HTML_LDCOMPLETE: e->etype = IAX_EVENT_LDCOMPLETE; return schedule_delivery(e, ts); case AST_HTML_UNLINK: e->etype = IAX_EVENT_UNLINK; return schedule_delivery(e, ts); case AST_HTML_LINKREJECT: e->etype = IAX_EVENT_LINKREJECT; return schedule_delivery(e, ts); default: DEBU(G "Don't know how to handle HTML type %d frames\n", fh->csub); free(e); return NULL; } break; default: DEBU(G "Don't know what to do with frame type %d\n", fh->type); free(e); return NULL; } } else DEBU(G "Out of memory\n"); return NULL;}static struct iax_event *iax_miniheader_to_event(struct iax_session *session, struct iax_mini_hdr *mh, int datalen){ struct iax_event *e; unsigned int ts; e = (struct iax_event *)malloc(sizeof(struct iax_event)); if (e) { if (session->voiceformat > 0) { e->etype = IAX_EVENT_VOICE; e->session = session; e->event.voice.format = session->voiceformat; if (datalen) {#ifdef EXTREME_DEBUG DEBU(G "%d bytes of voice\n", datalen);#endif e->event.voice.data = (char *)malloc(datalen); if (e->event.voice.data) { e->event.voice.datalen = datalen; memcpy(e->event.voice.data, mh->data, datalen); } else { free(e); e = NULL; DEBU(G "Out of memory\n"); return e; } } else { /* Empty voice frame? Maybe it could happen... */ e->event.voice.data = NULL; e->event.voice.datalen = 0; } ts = (session->last_ts & 0xFFFF0000) | ntohs(mh->ts); return schedule_delivery(e, ts); } else { DEBU(G "No last format received on session %d\n", session->callno); free(e); e = NULL; } } else DEBU(G "Out of memory\n"); return e;}static struct iax_event *iax_net_read(void){ char buf[IAX_MAX_BUF_SIZE]; int res; struct sockaddr_in sin; int sinlen; struct iax_full_hdr *fh = (struct iax_full_hdr *)buf; struct iax_mini_hdr *mh = (struct iax_mini_hdr *)buf; struct iax_session *session; sinlen = sizeof(sin); res = recvfrom(netfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &sinlen); buf[sizeof(buf) - 1] = '\0'; if (res < 0) {#ifdef WIN32 if (WSAGetLastError() != WSAEWOULDBLOCK) { DEBU(G "Error on read: %d\n", WSAGetLastError()); IAXERROR "Read error on network socket: %s", strerror(errno)); }#else if (errno != EAGAIN) { DEBU(G "Error on read: %s\n", strerror(errno)); IAXERROR "Read error on network socket: %s", strerror(errno)); }#endif return NULL; } if (ntohs(fh->callno) & IAX_FLAG_FULL) { /* Full size header */ if (res < sizeof(struct iax_full_hdr)) { DEBU(G "Short header received from %s\n", inet_ntoa(sin.sin_addr)); IAXERROR "Short header received from %s\n", inet_ntoa(sin.sin_addr)); } /* We have a full header, process appropriately */ session = iax_find_session(&sin, (short)(ntohs((short)fh->callno) & ~IAX_FLAG_FULL), ntohs((short)fh->dcallno), 1); if (session) return iax_header_to_event(session, fh, res - sizeof(struct iax_full_hdr)); DEBU(G "No session?\n"); return NULL; } else { if (res < sizeof(struct iax_mini_hdr)) { DEBU(G "Short header received from %s\n", inet_ntoa(sin.sin_addr)); IAXERROR "Short header received from %s\n", inet_ntoa(sin.sin_addr)); } /* Miniature, voice frame */ session = iax_find_session(&sin, ntohs(fh->callno), 0, 0); if (session) return iax_miniheader_to_event(session, mh, res - sizeof(struct iax_mini_hdr)); DEBU(G "No session?\n"); return NULL; }}static struct iax_sched *iax_get_sched(struct timeval tv){ struct iax_sched *cur, *prev=NULL; cur = schedq; /* Check the event schedule first. */ while(cur) { if ((tv.tv_sec > cur->when.tv_sec) || ((tv.tv_sec == cur->when.tv_sec) && (tv.tv_usec >= cur->when.tv_usec))) { /* Take it out of the event queue */ if (prev) { prev->next = cur->next; } else { schedq = cur->next; } return cur; } cur = cur->next; } return NULL;}struct iax_event *iax_get_event(int blocking){ struct iax_event *event; struct iax_frame *frame; struct timeval tv; struct iax_sched *cur; struct iax_event e; gettimeofday(&tv, NULL); while((cur = iax_get_sched(tv))) { event = cur->event; frame = cur->frame; if (event) { /* See if this is an event we need to handle */ event = handle_event(event); if (event) { free(cur); return event; } } else { /* It's a frame, transmit it and schedule a retry */ if (frame->retries < 0) { /* It's been acked. No need to send it. Destroy the old frame */ if (frame->data) free(frame->data); free(frame); } else if (frame->retries == 0) { if (frame->transferpacket) { /* Send a transfer reject since we weren't able to connect */ e.etype = IAX_EVENT_TXREJECT; iax_do_event(frame->session, &e); break; } else { /* We haven't been able to get an ACK on this packet. We should destroy its session */ event = (struct iax_event *)malloc(sizeof(struct iax_event)); if (event) { event->etype = IAX_EVENT_TIMEOUT; event->session = frame->session; free(cur); return handle_event(event); } } } else { /* Decrement remaining retries */ frame->retries--; /* Multiply next retry time by 4, not above MAX_RETRY_TIME though */ frame->retrytime *= 4; /* Keep under 1000 ms if this is a transfer packet */ if (!frame->transferpacket) { if (frame->retrytime > MAX_RETRY_TIME) frame->retrytime = MAX_RETRY_TIME; } else if (frame->retrytime > 1000) frame->retrytime = 1000; iax_xmit_frame(frame); /* Schedule another retransmission */ printf("Scheduling retransmission %d\n", frame->retries); iax_sched_event(NULL, frame, frame->retrytime); } } free(cur); } /* Now look for networking events */ if (blocking) { /* Block until there is data if desired */ fd_set fds; FD_ZERO(&fds); FD_SET(netfd, &fds); select(netfd + 1, &fds, NULL, NULL, NULL); } event = iax_net_read(); return handle_event(event);}struct sockaddr_in iax_get_peer_addr(struct iax_session *session){ return session->peeraddr;}void iax_event_free(struct iax_event *event){ switch(event->etype) { case IAX_EVENT_CONNECT: if (event->event.connect.callerid) free(event->event.connect.callerid); if (event->event.connect.dnid) free(event->event.connect.dnid); if (event->event.connect.context) free(event->event.connect.context); if (event->event.connect.exten) free(event->event.connect.exten); if (event->event.connect.username) free(event->event.connect.username); if (event->event.connect.hostname) free(event->event.connect.hostname); if (event->event.connect.language) free(event->event.connect.language); break; case IAX_EVENT_HANGUP: if (event->event.hangup.byemsg) free(event->event.hangup.byemsg); break; case IAX_EVENT_REJECT: if (event->event.reject.reason) free(event->event.reject.reason); break; case IAX_EVENT_VOICE: if (event->event.voice.data) free(event->event.voice.data); break; case IAX_EVENT_IMAGE: if (event->event.image.data) free(event->event.image.data); break; case IAX_EVENT_URL: if (event->event.url.url) free(event->event.url.url); break; case IAX_EVENT_AUTHRQ: if (event->event.authrequest.challenge) free(event->event.authrequest.challenge); if (event->event.authrequest.username) free(event->event.authrequest.username); break; case IAX_EVENT_AUTHRP: if (event->event.authreply.reply) free(event->event.authreply.reply); break; case IAX_EVENT_REGREQ: if (event->event.regrequest.server) free(event->event.regrequest.server); if (event->event.regrequest.peer) free(event->event.regrequest.peer); if (event->event.regrequest.secret) free(event->event.regrequest.secret); break; case IAX_EVENT_REGREP: if (event->event.regreply.ourip) free(event->event.regreply.ourip); if (event->event.regreply.callerid) free(event->event.regreply.callerid); break; case IAX_EVENT_TRANSFER: if (event->event.transfer.newip) free(event->event.transfer.newip); break; case IAX_EVENT_DPREQ: if (event->event.dpreq.number) free(event->event.dpreq.number); break; case
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -