/* * Copyright (C) 2004-2005 by Objective Systems, Inc. * * This software is furnished under an open source license and may be * used and copied only in accordance with the terms of this license. * The text of the license may generally be found in the root * directory of this installation in the COPYING file. It * can also be viewed online at the following URL: * * http://www.obj-sys.com/open/license.html * * Any redistributions of this file including modified versions must * maintain this copyright notice. * *****************************************************************************/ #include "asterisk.h" #include "asterisk/lock.h" #include "ooStackCmds.h" #include "ootrace.h" #include "ooq931.h" #include "ooh245.h" #include "ooh323ep.h" #include "oochannels.h" #include "ooCalls.h" #include "ooCmdChannel.h" /** Global endpoint structure */ extern OOH323EndPoint gH323ep; OOSOCKET gCmdChan = 0; ast_mutex_t gCmdChanLock; int ooCreateCmdConnection() { int ret = 0; int thePipe[2]; if ((ret = pipe(thePipe)) == -1) { return OO_FAILED; } ast_mutex_init(&gCmdChanLock); gH323ep.cmdSock = dup(thePipe[0]); close(thePipe[0]); gCmdChan = dup(thePipe[1]); close(thePipe[1]); return OO_OK; } int ooCreateCallCmdConnection(OOH323CallData* call) { int ret = 0; int thePipe[2]; OOTRACEINFO2("INFO: create cmd connect for call: %lx\n", call); call->CmdChanLock = calloc(1, sizeof(ast_mutex_t)); ast_mutex_init(call->CmdChanLock); if ((ret = socketpair(PF_LOCAL, SOCK_STREAM, 0, thePipe)) == -1) { ast_mutex_destroy(call->CmdChanLock); free(call->CmdChanLock); call->CmdChanLock = NULL; return OO_FAILED; } ast_mutex_lock(call->CmdChanLock); call->cmdSock = thePipe[0]; call->CmdChan = thePipe[1]; ast_mutex_unlock(call->CmdChanLock); return OO_OK; } int ooCloseCmdConnection() { close(gH323ep.cmdSock); gH323ep.cmdSock = 0; close(gCmdChan); gCmdChan = 0; ast_mutex_destroy(&gCmdChanLock); return OO_OK; } int ooCloseCallCmdConnection(OOH323CallData* call) { ast_mutex_lock(call->CmdChanLock); close(call->cmdSock); call->cmdSock = 0; close(call->CmdChan); call->CmdChan = 0; ast_mutex_unlock(call->CmdChanLock); ast_mutex_destroy(call->CmdChanLock); free(call->CmdChanLock); call->CmdChanLock = NULL; return OO_OK; } int ooWriteStackCommand(OOStackCommand *cmd) { ast_mutex_lock(&gCmdChanLock); if (write(gCmdChan, (char*)cmd, sizeof(OOStackCommand)) == -1) { ast_mutex_unlock(&gCmdChanLock); return OO_FAILED; } ast_mutex_unlock(&gCmdChanLock); return OO_OK; } int ooWriteCallStackCommand(OOH323CallData* call, OOStackCommand *cmd) { unsigned char buffer[MAXMSGLEN]; unsigned char* bPoint; memcpy(buffer, cmd, sizeof(OOStackCommand)); bPoint = buffer + sizeof(OOStackCommand); if (cmd->param1 && cmd->plen1 > 0) { if (bPoint + cmd->plen1 >= buffer + MAXMSGLEN) return OO_FAILED; memcpy(bPoint, cmd->param1, cmd->plen1); bPoint += cmd->plen1; } if (cmd->param2 && cmd->plen2 > 0) { if (bPoint + cmd->plen2 >= buffer + MAXMSGLEN) return OO_FAILED; memcpy(bPoint, cmd->param2, cmd->plen2); bPoint += cmd->plen2; } if (cmd->param3 && cmd->plen3 > 0) { if (bPoint + cmd->plen3 >= buffer + MAXMSGLEN) return OO_FAILED; memcpy(bPoint, cmd->param3, cmd->plen3); bPoint += cmd->plen3; } ast_mutex_lock(call->CmdChanLock); if (write(call->CmdChan, buffer, bPoint - buffer) == -1) { ast_mutex_unlock(call->CmdChanLock); return OO_FAILED; } ast_mutex_unlock(call->CmdChanLock); return OO_OK; } int ooReadAndProcessStackCommand() { OOH323CallData *pCall = NULL; unsigned char buffer[MAXMSGLEN]; int i, recvLen = 0; OOStackCommand cmd; memset(&cmd, 0, sizeof(OOStackCommand)); ast_mutex_lock(&gCmdChanLock); recvLen = read(gH323ep.cmdSock, buffer, MAXMSGLEN); ast_mutex_unlock(&gCmdChanLock); if(recvLen <= 0) { OOTRACEERR1("Error:Failed to read CMD message\n"); return OO_FAILED; } for(i=0; (int)(i+sizeof(OOStackCommand)) <= recvLen; i += sizeof(OOStackCommand)) { memcpy(&cmd, buffer+i, sizeof(OOStackCommand)); if(cmd.type == OO_CMD_NOOP) continue; if(gH323ep.gkClient && gH323ep.gkClient->state != GkClientRegistered) { OOTRACEINFO1("Ignoring stack command as Gk Client is not registered" " yet\n"); } else { switch(cmd.type) { case OO_CMD_MAKECALL: OOTRACEINFO2("Processing MakeCall command %s\n", (char*)cmd.param2); ooH323NewCall ((char*)cmd.param2); break; case OO_CMD_MANUALPROGRESS: pCall = ooFindCallByToken((char*)cmd.param1); if(!pCall) { OOTRACEINFO2("Call \"%s\" does not exist\n", (char*)cmd.param1); OOTRACEINFO1("Call migth be cleared/closed\n"); } else { ooSendProgress(ooFindCallByToken((char*)cmd.param1)); } break; case OO_CMD_MANUALRINGBACK: if(OO_TESTFLAG(gH323ep.flags, OO_M_MANUALRINGBACK)) { pCall = ooFindCallByToken((char*)cmd.param1); if(!pCall) { OOTRACEINFO2("Call \"%s\" does not exist\n", (char*)cmd.param1); OOTRACEINFO1("Call migth be cleared/closed\n"); } else { ooSendAlerting(ooFindCallByToken((char*)cmd.param1)); if(OO_TESTFLAG(gH323ep.flags, OO_M_AUTOANSWER)) { ooSendConnect(ooFindCallByToken((char*)cmd.param1)); } } } break; case OO_CMD_ANSCALL: pCall = ooFindCallByToken((char*)cmd.param1); if(!pCall) { OOTRACEINFO2("Call \"%s\" does not exist\n", (char*)cmd.param1); OOTRACEINFO1("Call might be cleared/closed\n"); } else { OOTRACEINFO2("Processing Answer Call command for %s\n", (char*)cmd.param1); ooSendConnect(pCall); } break; case OO_CMD_FWDCALL: OOTRACEINFO3("Forwarding call %s to %s\n", (char*)cmd.param1, (char*)cmd.param2); ooH323ForwardCall((char*)cmd.param1, (char*)cmd.param2); break; case OO_CMD_HANGCALL: OOTRACEINFO3("Processing Hang call command %s with q931 cause %d\n", (char*)cmd.param1, *(int *) cmd.param3); ooH323HangCall((char*)cmd.param1, *(OOCallClearReason*)cmd.param2, *(int *) cmd.param3); break; case OO_CMD_SENDDIGIT: pCall = ooFindCallByToken((char*)cmd.param1); if(!pCall) { OOTRACEERR2("ERROR:Invalid calltoken %s\n", (char*)cmd.param1); break; } if(pCall->jointDtmfMode & OO_CAP_DTMF_H245_alphanumeric) { ooSendH245UserInputIndication_alphanumeric( pCall, (const char*)cmd.param2); } else if(pCall->jointDtmfMode & OO_CAP_DTMF_H245_signal) { ooSendH245UserInputIndication_signal( pCall, (const char*)cmd.param2); } else { ooQ931SendDTMFAsKeyPadIE(pCall, (const char*)cmd.param2); } break; case OO_CMD_STOPMONITOR: OOTRACEINFO1("Processing StopMonitor command\n"); ooStopMonitorCalls(); break; default: OOTRACEERR1("ERROR:Unknown command\n"); } } if(cmd.param1) free(cmd.param1); if(cmd.param2) free(cmd.param2); if(cmd.param3) free(cmd.param3); } return OO_OK; } int ooReadAndProcessCallStackCommand(OOH323CallData* call) { unsigned char buffer[MAXMSGLEN]; unsigned char *bPoint; int recvLen = 0; OOStackCommand cmd; memset(&cmd, 0, sizeof(OOStackCommand)); if (call->CmdChanLock) { ast_mutex_lock(call->CmdChanLock); recvLen = read(call->cmdSock, buffer, MAXMSGLEN); ast_mutex_unlock(call->CmdChanLock); } else { recvLen = read(call->cmdSock, buffer, MAXMSGLEN); } if(recvLen <= 0) { OOTRACEERR1("Error:Failed to read CMD message\n"); return OO_FAILED; } bPoint = buffer; while (bPoint < buffer + recvLen - sizeof(OOStackCommand)) { memcpy(&cmd, bPoint, sizeof(OOStackCommand)); bPoint += sizeof(OOStackCommand); if (cmd.plen1 > 0) { cmd.param1 = malloc(cmd.plen1 + 1); if (!cmd.param1) return OO_FAILED; memset(cmd.param1, 0, cmd.plen1 + 1); memcpy(cmd.param1, bPoint, cmd.plen1); bPoint += cmd.plen1; } if (cmd.plen2 > 0) { cmd.param2 = malloc(cmd.plen2 + 1); if (!cmd.param2) return OO_FAILED; memset(cmd.param2, 0, cmd.plen2 + 1); memcpy(cmd.param2, bPoint, cmd.plen2); bPoint += cmd.plen2; } if (cmd.plen3 > 0) { cmd.param3 = malloc(cmd.plen3 + 1); if (!cmd.param3) return OO_FAILED; memset(cmd.param3, 0, cmd.plen3 + 1); memcpy(cmd.param3, bPoint, cmd.plen3); bPoint += cmd.plen3; } if(cmd.type == OO_CMD_NOOP) continue; if(gH323ep.gkClient && gH323ep.gkClient->state != GkClientRegistered) { OOTRACEINFO1("Ignoring stack command as Gk Client is not registered" " yet\n"); } else { switch(cmd.type) { case OO_CMD_MAKECALL: OOTRACEINFO2("Processing MakeCall command %s\n", (char*)cmd.param2); ooH323MakeCall ((char*)cmd.param1, (char*)cmd.param2, (ooCallOptions*)cmd.param3); break; case OO_CMD_MANUALPROGRESS: ooSendProgress(call); break; case OO_CMD_MANUALRINGBACK: if(OO_TESTFLAG(gH323ep.flags, OO_M_MANUALRINGBACK)) { ooSendAlerting(call); if(OO_TESTFLAG(gH323ep.flags, OO_M_AUTOANSWER)) { ooSendConnect(call); } } break; case OO_CMD_ANSCALL: ooSendConnect(call); break; case OO_CMD_FWDCALL: OOTRACEINFO3("Forwarding call %s to %s\n", (char*)cmd.param1, (char*)cmd.param2); ooH323ForwardCall((char*)cmd.param1, (char*)cmd.param2); break; case OO_CMD_HANGCALL: OOTRACEINFO2("Processing Hang call command %s with q931 cause %d\n", (char*)cmd.param1); ooH323HangCall((char*)cmd.param1, *(OOCallClearReason*)cmd.param2, *(int *) cmd.param3); break; case OO_CMD_SENDDIGIT: if(call->jointDtmfMode & OO_CAP_DTMF_H245_alphanumeric) { ooSendH245UserInputIndication_alphanumeric( call, (const char*)cmd.param2); } else if(call->jointDtmfMode & OO_CAP_DTMF_H245_signal) { ooSendH245UserInputIndication_signal( call, (const char*)cmd.param2); } else { ooQ931SendDTMFAsKeyPadIE(call, (const char*)cmd.param2); } break; case OO_CMD_REQMODE: OOTRACEINFO3("Processing RequestMode command %s, requested mode is %d\n", (char *)cmd.param1, *(int *)cmd.param2); ooSendRequestMode(call, *(int *)cmd.param2); break; case OO_CMD_SETANI: OOTRACEINFO3("Processing SetANI command %s, ani is %s\n", (char *)cmd.param1, (char *)cmd.param2); if(cmd.param2) { strncpy(call->ourCallerId, cmd.param2, sizeof(call->ourCallerId)-1); call->ourCallerId[sizeof(call->ourCallerId)-1] = '\0'; } break; default: OOTRACEERR1("ERROR:Unknown command\n"); } } if(cmd.param1) free(cmd.param1); if(cmd.param2) free(cmd.param2); if(cmd.param3) free(cmd.param3); } return OO_OK; }