📄 iax.c
字号:
"TKOFFHK ", "OFFHOOK" }; struct iax_full_hdr *fh; char retries[20]; char class2[20]; char subclass2[20]; char *class; char *subclass; if (f) { fh = f->data; snprintf(retries, sizeof(retries), "%03d", f->retries); } else { strcpy(retries, "N/A"); fh = fhi; } if (!(ntohs(fh->callno) & IAX_FLAG_FULL)) { /* Don't mess with mini-frames */ return; } if ((fh->type >= sizeof(frames)/sizeof(char *)) || (fh->type < 0)) { snprintf(class2, sizeof(class2), "(%d?)", fh->type); class = class2; } else { class = frames[(int)fh->type]; } if (fh->type == AST_FRAME_DTMF) { sprintf(subclass2, "%c", fh->csub); subclass = subclass2; } else if (fh->type == AST_FRAME_IAX) { if (fh->csub >= sizeof(iaxs)/sizeof(iaxs[0])) { snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub); subclass = subclass2; } else { subclass = iaxs[(int)fh->csub]; } } else if (fh->type == AST_FRAME_CONTROL) { if (fh->csub > sizeof(cmds)/sizeof(char *)) { snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->csub); subclass = subclass2; } else { subclass = cmds[(int)fh->csub]; } } else { snprintf(subclass2, sizeof(subclass2), "%d", fh->csub); subclass = subclass2; } if (debug) { fprintf(stderr, "%s-Frame Retry[%s] -- Seqno: %2.2d Type: %s Subclass: %s\n", (rx ? "Rx" : "Tx"), retries, ntohs(fh->seqno), class, subclass); fprintf(stderr, " Timestamp: %05dms Callno: %4.4d DCall: %4.4d\n", ntohl(fh->ts), ntohs(fh->callno) & ~IAX_FLAG_FULL, (short) ntohs(fh->dcallno)); }}#endifstatic int iax_xmit_frame(struct iax_frame *f){ /* Send the frame raw */#ifdef DEBUG_SUPPORT showframe(f, NULL, 0);#endif return sendto(netfd, (const char *) f->data, f->datalen,#ifdef WIN32 0,#else MSG_DONTWAIT | MSG_NOSIGNAL,#endif f->transferpacket ? (struct sockaddr *)&(f->session->transfer) : (struct sockaddr *)&(f->session->peeraddr), sizeof(f->session->peeraddr));}static int iax_reliable_xmit(struct iax_frame *f){ struct iax_frame *fc; struct iax_full_hdr *fh; fh = (struct iax_full_hdr *) f->data; if (!fh->type) { DEBU(G "Asked to reliably transmit a non-packet. Crashing.\n"); *((char *)0)=0; } fc = (struct iax_frame *)malloc(sizeof(struct iax_frame)); if (fc) { /* Make a copy of the frame */ memcpy(fc, f, sizeof(struct iax_frame)); /* And a copy of the data if applicable */ if (!fc->data || !fc->datalen) { IAXERROR "No frame data?"); DEBU(G "No frame data?\n"); return -1; } else { fc->data = (char *)malloc(fc->datalen); if (!fc->data) { DEBU(G "Out of memory\n"); IAXERROR "Out of memory\n"); return -1; } memcpy(fc->data, f->data, f->datalen); iax_sched_event(NULL, fc, fc->retrytime); return iax_xmit_frame(fc); } } else return -1;}int iax_init(int preferredportno){ int portno = preferredportno; struct sockaddr_in sin; int sinlen; int flags; if (netfd > -1) { /* Sokay, just don't do anything */ DEBU(G "Already initialized."); return 0; } netfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (netfd < 0) { DEBU(G "Unable to allocate UDP socket\n"); IAXERROR "Unable to allocate UDP socket\n"); return -1; } if (preferredportno == 0) preferredportno = IAX_DEFAULT_PORTNO; if (preferredportno > 0) { sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; sin.sin_port = htons((short)preferredportno); if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { DEBU(G "Unable to bind to preferred port. Using random one instead."); } } sinlen = sizeof(sin); if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0) { close(netfd); netfd = -1; DEBU(G "Unable to figure out what I'm bound to."); IAXERROR "Unable to determine bound port number."); }#ifdef WIN32 flags = 1; if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags)) { _close(netfd); netfd = -1; DEBU(G "Unable to set non-blocking mode."); IAXERROR "Unable to set non-blocking mode."); } #else if ((flags = fcntl(netfd, F_GETFL)) < 0) { close(netfd); netfd = -1; DEBU(G "Unable to retrieve socket flags."); IAXERROR "Unable to retrieve socket flags."); } if (fcntl(netfd, F_SETFL, flags | O_NONBLOCK) < 0) { close(netfd); netfd = -1; DEBU(G "Unable to set non-blocking mode."); IAXERROR "Unable to set non-blocking mode."); }#endif portno = ntohs(sin.sin_port); srand(time(NULL)); callnums = rand() % 32767 + 1; DEBU(G "Started on port %d\n", portno); return portno; }static void destroy_session(struct iax_session *session);static void convert_reply(char *out, unsigned char *in){ int x; for (x=0;x<16;x++) out += sprintf(out, "%2.2x", (int)in[x]);}static unsigned char compress_subclass(int subclass){ int x; int power=-1; /* If it's 128 or smaller, just return it */ if (subclass < IAX_FLAG_SC_LOG) return subclass; /* Otherwise find its power */ for (x = 0; x < IAX_MAX_SHIFT; x++) { if (subclass & (1 << x)) { if (power > -1) { DEBU(G "Can't compress subclass %d\n", subclass); return 0; } else power = x; } } return power | IAX_FLAG_SC_LOG;}int iax_do_event(struct iax_session *session, struct iax_event *event){ struct iax_frame f; int left; struct hostent *hp; unsigned int ts; char buf[32768]; struct iax_full_hdr *fh = (struct iax_full_hdr *)buf; struct iax_mini_hdr *mh = (struct iax_mini_hdr *)buf; struct MD5Context md5; char reply[32]; char realreply[80]; char *requeststr = fh->data;#define MYSNPRINTF snprintf(requeststr + strlen(requeststr), sizeof(buf) - sizeof(struct iax_full_hdr) - strlen(requeststr), bzero(buf, sizeof(buf)); /* Default some things in the frame */ f.session = session; f.data = buf; f.datalen = sizeof(struct iax_full_hdr); left = sizeof(buf) - f.datalen; f.retries = maxretries; f.transferpacket = 0; /* Assume a full header and default some things */ fh->callno = htons((short)(session->callno | IAX_FLAG_FULL)); fh->dcallno = htons((short)session->peercallno); /* Calculate timestamp */ fh->ts = htonl(calc_timestamp(session, 0)); /* Start by using twice the pingtime */ f.retrytime = session->pingtime * 2; if (f.retrytime > MAX_RETRY_TIME) f.retrytime = MAX_RETRY_TIME; if (f.retrytime < MIN_RETRY_TIME) f.retrytime = MIN_RETRY_TIME; f.next = NULL; /* Some sanity checks */ if (!event) { DEBU(G "Event is null?\n"); IAXERROR "Null event"); return -1; } if (!session) session = event->session; if (!iax_session_valid(session)) { DEBU(G "Session invalid for sending event\n"); IAXERROR "Invalid session for transmitting event"); } /* Send (possibly reliably) the correct frame given the kind of event requested */ switch(event->etype) { case IAX_EVENT_CONNECT: /* Connect first */ hp = gethostbyname(event->event.connect.hostname); if (!hp) { snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", event->event.connect.hostname); return -1; } memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr)); session->peeraddr.sin_port = htons(event->event.connect.portno); session->peeraddr.sin_family = AF_INET; fh->type = AST_FRAME_IAX; fh->csub = IAX_COMMAND_NEW; fh->seqno = htons(session->oseqno++); if (event->event.connect.exten) MYSNPRINTF "exten=%s;", event->event.connect.exten); if (event->event.connect.callerid) MYSNPRINTF "callerid=%s;", event->event.connect.callerid); if (event->event.connect.dnid) MYSNPRINTF "dnid=%s;", event->event.connect.dnid); if (event->event.connect.context) MYSNPRINTF "context=%s;", event->event.connect.context); if (event->event.connect.username) MYSNPRINTF "username=%s;", event->event.connect.username); if (event->event.connect.language) MYSNPRINTF "language=%s;", event->event.connect.language); MYSNPRINTF "formats=%d;", sformats); MYSNPRINTF "version=%d;", IAX_PROTO_VERSION); f.datalen += strlen(requeststr); iax_reliable_xmit(&f); break; case IAX_EVENT_REREQUEST: fh->type = AST_FRAME_IAX; fh->csub = IAX_COMMAND_REGREQ; fh->seqno = htons(session->oseqno++); MYSNPRINTF "peer=%s;refresh=%d;", session->peer, session->refresh); if (strstr(session->methods, "md5")) { MD5Init(&md5); MD5Update(&md5, (const unsigned char *) &session->challenge[0], strlen(session->challenge)); MD5Update(&md5, (const unsigned char *) &session->secret[0], strlen(session->secret)); MD5Final((unsigned char *) reply, &md5); memset(realreply, 0, sizeof(realreply)); convert_reply(realreply, (unsigned char *) &reply[0]); MYSNPRINTF "md5secret=%s;", realreply); } else { MYSNPRINTF "secret=%s;", session->secret); } f.datalen += strlen(requeststr); iax_reliable_xmit(&f); break; case IAX_EVENT_REGREQ: /* Connect first */ hp = gethostbyname(event->event.regrequest.server); if (!hp) { snprintf(iax_errstr, sizeof(iax_errstr), "Invalid hostname: %s", event->event.regrequest.server); return -1; } memcpy(&session->peeraddr.sin_addr, hp->h_addr, sizeof(session->peeraddr.sin_addr)); session->peeraddr.sin_port = htons(event->event.regrequest.portno); session->peeraddr.sin_family = AF_INET; fh->type = AST_FRAME_IAX; fh->csub = IAX_COMMAND_REGREQ; fh->seqno = htons(session->oseqno++); if (event->event.regrequest.secret) strncpy(session->secret, event->event.regrequest.secret, sizeof(session->secret)-1); else strcpy(session->secret, ""); if (event->event.regrequest.peer) { MYSNPRINTF "peer=%s;", event->event.regrequest.peer); strncpy(session->peer, event->event.regrequest.peer, sizeof(session->peer)-1); } else strcpy(session->peer, ""); if (event->event.regrequest.refresh) { MYSNPRINTF "refresh=%d;", event->event.regrequest.refresh); session->refresh = event->event.regrequest.refresh; } else session->refresh = 0; f.datalen += strlen(requeststr); iax_reliable_xmit(&f); break; case IAX_EVENT_AUTHRP: fh->type = AST_FRAME_IAX; fh->csub = IAX_COMMAND_AUTHREP; fh->seqno = htons(session->oseqno++); if (event->event.authreply.authmethod == IAX_AUTHMETHOD_MD5) { snprintf(requeststr, left, "md5secret=%s;", event->event.authreply.reply); } else if (event->event.authreply.authmethod == IAX_AUTHMETHOD_PLAINTEXT) { snprintf(requeststr, left, "secret=%s;", event->event.authreply.reply); } else { DEBU(G "Unknown auth method: %d\n", event->event.authreply.authmethod); IAXERROR "Invalid authentication method %d\n", event->event.authreply.authmethod); return -1; } f.datalen += strlen(requeststr); iax_reliable_xmit(&f); break; case IAX_EVENT_LAGRP: /* Special case -- return the original timestamp in the message instead of our own. */ fh->type = AST_FRAME_IAX; fh->csub = IAX_COMMAND_LAGRP; fh->ts = htonl(event->event.lagrq.ts); fh->seqno = htons(session->oseqno++); iax_reliable_xmit(&f); break; case IAX_EVENT_DTMF: /* Send a DTMF tone as a reliable transmission -- easy */ fh->type = AST_FRAME_DTMF; fh->seqno = htons(session->oseqno++); fh->csub = event->event.dtmf.digit; iax_reliable_xmit(&f); break; case IAX_EVENT_RINGA: /* Announce that we are ringing */ fh->type = AST_FRAME_CONTROL; fh->seqno = htons(session->oseqno++); fh->csub = AST_CONTROL_RINGING; iax_reliable_xmit(&f); break; case IAX_EVENT_HANGUP: fh->type = AST_FRAME_IAX; fh->seqno = htons(session->oseqno++); fh->csub = IAX_COMMAND_HANGUP; if (event->event.hangup.byemsg) { strncpy(fh->data, event->event.hangup.byemsg, left-1); f.datalen += strlen(fh->data); } /* XXX Not really reliable since we turn right around and kill it XXX */ iax_reliable_xmit(&f); destroy_session(session); break; case IAX_EVENT_REJECT: fh->type = AST_FRAME_IAX; fh->seqno = htons(session->oseqno++); fh->csub = IAX_COMMAND_REJECT; strncpy(fh->data, event->event.reject.reason, left-1); f.datalen += strlen(fh->data); /* XXX Not really reliable since we turn right around and kill it XXX */ iax_reliable_xmit(&f); destroy_session(session); break; case IAX_EVENT_BUSY: fh->type = AST_FRAME_CONTROL; fh->seqno = htons(session->oseqno++); fh->csub = AST_CONTROL_BUSY; /* XXX Not really reliable since we turn right around and kill it XXX */ iax_reliable_xmit(&f); destroy_session(session); break; case IAX_EVENT_ACCEPT: fh->type = AST_FRAME_IAX; fh->seqno = htons(session->oseqno++); fh->csub = IAX_COMMAND_ACCEPT; f.datalen += snprintf((char *)(fh->data), left, "formats=%d;", sformats); f.datalen++; iax_reliable_xmit(&f); break; case IAX_EVENT_LAGRQ: fh->type = AST_FRAME_IAX; fh->seqno = htons(session->oseqno++); fh->csub = IAX_COMMAND_LAGRQ; iax_reliable_xmit(&f); break; case IAX_EVENT_ANSWER: fh->type = AST_FRAME_CONTROL; fh->seqno = htons(session->oseqno++); fh->csub = AST_CONTROL_ANSWER; iax_reliable_xmit(&f); break; case IAX_EVENT_PONG: fh->type = AST_FRAME_IAX; fh->csub = IAX_COMMAND_PONG; fh->ts = htonl(event->event.ping.ts); iax_reliable_xmit(&f); break; case IAX_EVENT_URL: fh->type = AST_FRAME_HTML; fh->seqno = htons(session->oseqno++); if (event->event.url.link) fh->csub = AST_HTML_LINKURL; else fh->csub = AST_HTML_URL; if (event->event.url.url) { f.datalen += strlen(event->event.url.url) + 1; strcpy(fh->data, event->event.url.url); } iax_reliable_xmit(&f); break; case IAX_EVENT_TEXT: fh->type = AST_FRAME_TEXT; fh->seqno = htons(session->oseqno++); fh->csub = AST_FRAME_TEXT; f.datalen += strlen(event->event.text.text) + 1; strcpy(fh->data, event->event.text.text); iax_reliable_xmit(&f); break; case IAX_EVENT_UNLINK: fh->type = AST_FRAME_HTML; fh->seqno = htons(session->oseqno++); fh->csub = AST_HTML_UNLINK; iax_reliable_xmit(&f); break; case IAX_EVENT_LINKREJECT: fh->type = AST_FRAME_HTML; fh->seqno = htons(session->oseqno++); fh->csub = AST_HTML_LINKREJECT; iax_reliable_xmit(&f); break; case IAX_EVENT_LDCOMPLETE: fh->type = AST_FRAME_HTML; fh->seqno = htons(session->oseqno++);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -