package icssessionmanager import ( "runtime" "runtime/debug" "strconv" "strings" "time" "gitlab.com/cinnamon/voiceagent/icsconf" "gitlab.com/cinnamon/voiceagent/icserror" "gitlab.com/cinnamon/voiceagent/icshttpclient" "gitlab.com/cinnamon/voiceagent/icslog" "gitlab.com/cinnamon/voiceagent/icsnet" "gitlab.com/cinnamon/voiceagent/icspacketparser" "gitlab.com/cinnamon/voiceagent/recorddata/readcallsignal" "gitlab.com/cinnamon/voiceagent/recorddata/responsecs" ) ////////////////////////////////////////////////////////////////// //session operator func findSessionWithCallID(callId string) *IcsSession { sessions := getSessionInstance() for _, session := range sessions { session.m.Lock() if strings.Compare(session.callId, callId) == 0 { session.m.Unlock() return session } session.m.Unlock() } return nil } func findSessionWithStation(station string) *IcsSession { sessions := getSessionInstance() for _, session := range sessions { session.m.Lock() //fmt.Printf("findsessionWithStation: %s, %s\n", session.Station, station) if strings.Compare(session.Station, station) == 0 { session.m.Unlock() return session } session.m.Unlock() } return nil } func findSessionWithBotToken(token string) *IcsSession { sessions := getSessionInstance() for _, session := range sessions { session.m.Lock() //fmt.Printf("findsessionWithStation: %s, %s\n", session.Station, station) if strings.Compare(session.botToken, token) == 0 { session.m.Unlock() return session } session.m.Unlock() } return nil } func findSessionWithRTPPort(srcPort int, dstPort int) *IcsSession { sessions := getSessionInstance() for _, session := range sessions { session.m.Lock() if (session.srcPort == srcPort && session.dstPort == dstPort) || (session.srcPort == dstPort && session.dstPort == srcPort) { session.m.Unlock() return session } session.m.Unlock() } return nil } /* 미사용 코드로 임시 주석 처리 ( csma 210512 ) func FindSessionID(sip icspacketparser.SIP) (IcsSessionID, *icserror.IcsError) { callID := sip.GetCallID() if len(callID) > 0 { session := findSessionWithCallID(callID) if session != nil { return IcsSessionID(session.ID), nil } } return IcsSessionID(-1), icserror.ICSERRSESSNotFoundSession } */ func FindSession(data interface{}) (*IcsSession, *icserror.IcsError) { //func FindSession(sip icspacketparser.SIP) (*IcsSession, *icserror.IcsError) { switch v := data.(type) { case icspacketparser.SIP: sip := v callID := sip.GetCallID() /* if sip.Method == icspacketparser.ICS_SIP_METHOD_BYE || sip.Method == icspacketparser.ICS_SIP_METHOD_CANCEL { //fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>", callID) } */ if len(callID) > 0 { session := findSessionWithCallID(callID) if session != nil { return session, nil } } case icspacketparser.RTP: rtp := v srcPort := rtp.SrcAddr.Port dstPort := rtp.DstAddr.Port session := findSessionWithRTPPort(srcPort, dstPort) if session != nil { return session, nil } case *readcallsignal.CallSignal: //case icspacketparser.CallSignal: cs := v session := findSessionWithStation(cs.Station) //fmt.Println("FindSession cs!", cs.Station, cs, session) if session != nil { return session, nil } //default: //fmt.Printf(">>>>>>>>>>>>>>>>>>%v-----%T\n", v, v) } return nil, icserror.ICSERRSESSNotFoundSession } /* 미사용 코드로 임시 주석 처리 ( csma 200512 ) func AllocSessionID(callId string, direction bool) (IcsSessionID, *icserror.IcsError) { if len(callId) == 0 { return IcsSessionID(-1), icserror.ICSERRInvalidParam } sessions := getSessionInstance() var id int for _, session := range sessions { id++ if len(session.callId) == 0 { session.callId = callId session.direction = direction return IcsSessionID(session.ID), nil } } if id >= channelNum { return IcsSessionID(-1), icserror.ICSERRSESSMaxSessionNumber } return IcsSessionID(-1), icserror.ICSERRSESSNotFoundSession } */ func goid() int { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { return -1 } return id } func AllocSession(channelID string, serverID string, station string, callId string, direction bool) (*IcsSession, *icserror.IcsError) { /* if len(callId) == 0 { return nil, icserror.ICSERRInvalidParam } */ l := icslog.GetIcsLog() sessions := getSessionInstance() var id int = 0 for _, session := range sessions { id++ session.m.Lock() if len(session.Station) == 0 { //if len(session.callId) == 0 || len(session.Station) == 0 { session.ChannelID = channelID session.ServerID = serverID session.Station = station session.callId = callId session.direction = direction session.txSeq = -1 session.rxSeq = -1 session.isSTTStart = false /*///////////////// fname := fmt.Sprintf("./rx_%03d.voice.g729", id) session.rxFile, _ = os.OpenFile(fname, os.O_CREATE|os.O_WRONLY, 0644) fname = fmt.Sprintf("./tx_%03d.voice.g729", id) session.txFile, _ = os.OpenFile(fname, os.O_CREATE|os.O_WRONLY, 0644) */ ///////////////// session.m.Unlock() l.Printf(icslog.LOG_LEVEL_INFO, session.ID, "Session[%d] Allocated(%d). Station: %s ==========================", session.ID, session.goroutineID, session.Station) return session, nil } session.m.Unlock() } if id >= channelNum { return nil, icserror.ICSERRSESSMaxSessionNumber } return nil, icserror.ICSERRSESSNotFoundSession } func (s *IcsSession) RemoveSession() *icserror.IcsError { l := icslog.GetIcsLog() defer func() { if err := recover(); err != nil { switch v := err.(type) { case error: icserror.ICSERRNETNotConnectError.SetError(v) l.Printf(icslog.LOG_LEVEL_WARN, s.ID, "PANIC! %s\n%s", icserror.ICSERRNETNotConnectError.GetError().Error(), string(debug.Stack())) default: l.Print(icslog.LOG_LEVEL_WARN, s.ID, icserror.ICSERRNETNotConnectError.GetMessage()) } } }() //s.VoiceNeter.Close() //s.CallSignalNeter.Close() //id := s.ID //s = &IcsSession{ID: id} //s.rxFile.Close() //s.txFile.Close() e := &IcsSession{} s.m.Lock() s.eventSystem.ClearJob() s.callId = e.callId s.Station = e.Station s.srcPort = e.srcPort s.dstPort = e.dstPort s.direction = e.direction s.isStart = 0 s.dtmf = "" //bot s.url = e.url s.custid = e.custid s.sstation = e.sstation s.isFoundPayload = false if s.RxConverter != nil { s.RxConverter.Close() s.RxConverter = nil } if s.TxConverter != nil { s.TxConverter.Close() s.TxConverter = nil } s.botStatus = nil s.botToken = "" s.isSTTStart = false s.txSeq = -1 s.rxSeq = -1 s.MethodAutomata = 0 s.m.Unlock() l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Removed Session[%d] ==========================", s.goroutineID) return nil } func GetSession(sessionID IcsSessionID) (*IcsSession, *icserror.IcsError) { if sessionID < IcsSessionID(0) { return nil, icserror.ICSERRInvalidParam } sessions := getSessionInstance() return sessions[int(sessionID)], nil } func (s IcsSession) GetSessionID() IcsSessionID { return IcsSessionID(s.ID) } func (s *IcsSession) CheckSignalMethod(sip icspacketparser.SIP) *icserror.IcsError { if s.CheckAutomata(&sip) { if s.MethodAutomata != ICS_SIP_AUTOMATA_CANCEL { s.SetSessionMethod(sip) } } else { //fmt.Println("^^^^^", "unMatched Automata", s.MethodAutomata, sip.Method) } if sip.Method == icspacketparser.ICS_SIP_METHOD_SIP20 && strings.Contains(sip.Cseq, " BYE") || s.MethodAutomata == ICS_SIP_AUTOMATA_CANCEL && sip.Method == icspacketparser.ICS_SIP_METHOD_ACK { //fmt.Println("^^^^^", "call s.RemoveSession() sip.Method, s.MethodAutomata ", sip.Method, s.MethodAutomata) serr := s.RemoveSession() if serr != nil { //serr.Print() return serr } } return nil } ////////////////////////////////////////////////////////////////// // func (s *IcsSession) SetTimestamp(now time.Time) { s.lastTimestamp = now } func (s IcsSession) GetPayloadType() icspacketparser.PayloadType { return s.payloadType } func (s *IcsSession) GetDirection() bool { return s.direction } func (s IcsSession) GetCallID() string { return s.callId } func (s IcsSession) GetBotToken() string { return s.botToken } func (s *IcsSession) SetAgentConfig(agentconf *icsconf.AgentConfig) { s.AgentConfig = agentconf } func (s *IcsSession) FindAgentConfig(agentID string) *icsconf.AgentConfig { conf := icsconf.GetIcsConfig() //a := strings.SplitN(agentID, string(0), 2) for _, agentconf := range conf.AgentConfig { //fmt.Printf("308LINE iter: %d, [%v] [%v] [%v]\n", iter, []byte(agentconf.Name), []byte(agentID), []byte(a[0])) if strings.Contains(agentID, agentconf.Name) { //fmt.Println(">>>>", iter, agentconf.Name) return &agentconf } } return nil } func (s *IcsSession) SendVoiceGatewayByeSignal() { l := icslog.GetIcsLog() conf := icsconf.GetIcsConfig() agentname := s.AgentConfig.Name telno := s.botStatus.Data.TelNo l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "###### Start BYE Message!!!!!!!!!") r := responsecs.NewResponse(agentname, telno, responsecs.BYE_COMMAND, responsecs.RC_SUCCESS, 0) addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) wlen, werr := icsnet.SendByeSignal(&addr, nil, r.GetData()) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send BYE to Voice Gateway - %s [%+v]", werr.GetError(), s.TcpConn) } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent BYE message to VoiceGateway: %d", wlen) // 윗쪽에서 코드를 봐야함!! s.Stop() serr := s.RemoveSession() // 세션을 날려야 바로 전화를 걸었을때 새로 받아짐 if serr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "RemoveSession Error %s", serr.GetMessage()) } } func (s *IcsSession) SendVoiceGatewayBotByeSignal(url string, custid string, sstation string) { // Send Bot HANGUP Message l := icslog.GetIcsLog() conf := icsconf.GetIcsConfig() agentname := s.AgentConfig.Name telno := s.botStatus.Data.TelNo l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "###### Start BYE Message!!!!!!!!!") r := responsecs.NewResponse(agentname, telno, responsecs.BYE_COMMAND, responsecs.RC_SUCCESS, 0) addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) wlen, werr := icsnet.SendByeSignal(&addr, nil, r.GetData()) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send BYE to Voice Gateway - %s [%+v]", werr.GetError(), s.TcpConn) } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent BYE message to VoiceGateway and Bot: %d", wlen) processResp := icshttpclient.PostProcess(url, "HANGUP", "", custid, "ICS_RCP", s.callId, sstation, s.botToken, "") if processResp == nil { l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error") } //close voiceneter verr := s.VoiceNeter.Close() if verr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to close Voice port - %s", verr.GetError()) } else { l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Closed Voice port") } //close session s.Stop() serr := s.RemoveSession() if serr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "RemoveSession Error %s", serr.GetMessage()) } } ////////////////////////////////////////// //DTMF // add DTMF func (s *IcsSession) AddDtmf() { inputDtmf := s.cs.InOut if inputDtmf == "10" { inputDtmf = "#" } else if inputDtmf == "11" { inputDtmf = "*" } s.m.Lock() s.dtmf += inputDtmf s.m.Unlock() } // reset DTMF func (s *IcsSession) ResetDtmf() { s.m.Lock() s.dtmf = "" s.m.Unlock() } // get DTMF func (s *IcsSession) GetDtmf(dtmfEnd string) string { result := "" if s.botStatus.Data.MaxDigit == len(s.dtmf) || strings.Contains(s.dtmf, dtmfEnd) { // len check result = s.dtmf } else if strings.Contains(s.dtmf, "*") { result = s.custid } return result }