package icspacketparser import ( "strconv" "strings" "gitlab.com/cinnamon/voiceagent/icserror" "gitlab.com/cinnamon/voiceagent/icsnet" ) type IcsSipMethod int const ( ICS_SIP_METHOD_REGISTER IcsSipMethod = iota ICS_SIP_METHOD_INVITE ICS_SIP_METHOD_PUBLISH ICS_SIP_METHOD_OPTIONS ICS_SIP_METHOD_INFO ICS_SIP_METHOD_UPDATE ICS_SIP_METHOD_REFER ICS_SIP_METHOD_SUBSCRIBE ICS_SIP_METHOD_MESSAGE ICS_SIP_METHOD_NOTIFY ICS_SIP_METHOD_PRACK ICS_SIP_METHOD_ACK ICS_SIP_METHOD_BYE ICS_SIP_METHOD_CANCEL ICS_SIP_METHOD_SIP20 ICS_SIP_METHOD_NOT_FOUND ) func (arr IcsSipMethod) String() string { var strSipMethod = []string{ "ICS_SIP_METHOD_REGISTER", "ICS_SIP_METHOD_INVITE", "ICS_SIP_METHOD_PUBLISH", "ICS_SIP_METHOD_OPTIONS", "ICS_SIP_METHOD_INFO", "ICS_SIP_METHOD_UPDATE", "ICS_SIP_METHOD_REFER", "ICS_SIP_METHOD_SUBSCRIBE", "ICS_SIP_METHOD_MESSAGE", "ICS_SIP_METHOD_NOTIFY", "ICS_SIP_METHOD_PRACK", "ICS_SIP_METHOD_ACK", "ICS_SIP_METHOD_BYE", "ICS_SIP_METHOD_CANCEL", "ICS_SIP_METHOD_SIP20", "ICS_SIP_METHOD_NOT_FOUND", } return strSipMethod[int(arr)%len(strSipMethod)] } type SIP struct { Headers map[string][]string Method IcsSipMethod Version string Source string Via []string MaxForwards int64 Contact string To string // ToTag string From string // FromTag string RecordRoute string RequestURI string CallID string UserAgent string Allow string Supported string Cseq string ContentLength int64 ContentType string ResType string // direction bool Content *SDP SrcAddr *icsnet.IcsNetAddr DstAddr *icsnet.IcsNetAddr } func NewSIP() (sip SIP) { return sip } func NewSDP() (sdp SDP) { return sdp } func NewSDPMedia() (sdpMedia SDPMedia) { return sdpMedia } var sdpMediaType = []string{"m", "a"} func findSdpMedia(mediaType string) bool { for _, value := range sdpMediaType { if value == mediaType { return true } } return false } func (s *SIP) SipParser(byteArr []byte) (icserr *icserror.IcsError) { strSipLine := strings.Split(string(byteArr), "\n") isParserSIP := true sdp := NewSDP() sdpMedia := SDPMedia{} sdpMedias := []SDPMedia{} for line := range strSipLine { //fmt.Println("strSipLine[line]", len(strings.TrimSpace(strSipLine[line])), isParserSIP, strings.TrimSpace(strSipLine[line])) if line == 0 { s.parseFirstLineHeader(strings.TrimSpace(strSipLine[line])) } else { if isParserSIP && len(strings.TrimSpace(strSipLine[line])) == 0 { isParserSIP = false } else if !isParserSIP && len(strings.TrimSpace(strSipLine[line])) == 0 { break } else if !isParserSIP { if len(strings.TrimSpace(strSipLine[line])) > 0 { if len(strings.TrimSpace(strSipLine[line])) == 0 { return nil } splits := strings.SplitN(string(strings.TrimSpace(strSipLine[line])), "=", 2) if len(splits) < 2 { return nil } name := strings.TrimSpace(splits[0]) value := strings.TrimSpace(splits[1]) if findSdpMedia(name) { sdpMedia.setSdpMediaStruct(name, value) } else { sdp.setSdpStruct(name, value) } } } else { s.parseSip(strings.TrimSpace(strSipLine[line])) } } } sdpMedias = append(sdpMedias, sdpMedia) if isExistSdpMedia(sdpMedias) { sdp.Media = &sdpMedias } // fmt.Println("sdp.Version", sdp.Version) // fmt.Println("sdp.Owner", sdp.Owner) // fmt.Println("sdp.Session", sdp.Session) // fmt.Println("sdp.Connection", sdp.Connection) if isExistSdp(sdp) { s.Content = &sdp } return nil } func isExistSdpMedia(sdpMedias []SDPMedia) bool { for _, value := range sdpMedias { if len(value.MediaDescription) == 0 { return false } // TODO Media만 존재하고, attributes 가 없는 경우 처리 방법 // for _, val := range value.Attributes { // fmt.Println(val) // } } return true } func isExistSdp(sdp SDP) bool { if sdp.Version == 0 && sdp.Owner == "" && sdp.Session == "" && sdp.Connection == "" { return false } return true } func (s *SIP) parseFirstLineHeader(strSipLine string) (icserr *icserror.IcsError) { // fmt.Println(">>>>>>>>>>>parseFirstLineHeader", strSipLine) splits := strings.SplitN(strSipLine, " ", 3) if len(splits) < 3 { return icserror.ICSERRSIPHeader } icsSipMethod, err := GetSipMethod(splits[0], splits[1]) if icsSipMethod == ICS_SIP_METHOD_SIP20 { s.ResType = splits[1] } if err != nil { return icserror.ICSERRSIPHeader } s.Method = icsSipMethod s.Version = splits[2] s.Source = splits[1] return nil } func GetSipMethod(strMethod, strSource string) (icsSipMethod IcsSipMethod, icserr *icserror.IcsError) { for method := IcsSipMethod(0); method < ICS_SIP_METHOD_NOT_FOUND; method++ { switch strings.ToUpper(strMethod) { case "REGISTER": return ICS_SIP_METHOD_REGISTER, nil case "INVITE": return ICS_SIP_METHOD_INVITE, nil case "SIP/2.0": return ICS_SIP_METHOD_SIP20, nil case "PRACK": return ICS_SIP_METHOD_PRACK, nil case "ACK": return ICS_SIP_METHOD_ACK, nil case "BYE": return ICS_SIP_METHOD_BYE, nil case "REFER": return ICS_SIP_METHOD_REFER, nil case "NOTIFY": return ICS_SIP_METHOD_NOTIFY, nil case "CANCEL": return ICS_SIP_METHOD_CANCEL, nil case "INFO": return ICS_SIP_METHOD_INFO, nil case "OPTIONS": return ICS_SIP_METHOD_OPTIONS, nil case "SUBSCRIBE": return ICS_SIP_METHOD_SUBSCRIBE, nil case "PUBLISH": return ICS_SIP_METHOD_PUBLISH, nil case "UPDATE": return ICS_SIP_METHOD_UPDATE, nil } } return ICS_SIP_METHOD_NOT_FOUND, nil } func (s *SIP) parseSip(data string) (icserr *icserror.IcsError) { if len(data) == 0 { return nil } splits := strings.SplitN(string(data), ":", 2) if len(splits) < 2 { return nil } name := strings.TrimSpace(splits[0]) value := strings.TrimSpace(splits[1]) s.setSipStruct(name, value) return nil } func (s *SIP) setSipStruct(name string, value string) (icserr *icserror.IcsError) { switch strings.ToUpper(name) { case "VIA": s.Via = append(s.Via, value) return nil case "MAX-FORWARDS": numValue, err := strconv.ParseInt(value, 10, 64) if err != nil { return icserror.ICSERRSIPHeader } s.MaxForwards = numValue return nil case "FROM": s.From = value // splits := strings.SplitN(string(value), "tag=", 2) // if len(splits) < 2 { // s.FromTag = "" // } else { // s.FromTag = strings.TrimSpace(splits[1]) // } return nil case "TO": s.To = value return nil case "CALL-ID": s.CallID = value return nil case "CSEQ": // splits := strings.SplitN(string(value), " ", 2) // numValue, err := strconv.ParseInt(strings.TrimSpace(splits[0]), 10, 64) // if err != nil { // return icserror.ICSERRSIPHeader // } // s.Cseq = numValue s.Cseq = strings.ToUpper(value) return nil case "CONTACT": s.Contact = value return nil case "SUPPORTED": s.Supported = value return nil case "ALLOW": s.Allow = value return nil case "USER-AGENT": s.UserAgent = value return nil case "CONTENT-TYPE": s.ContentType = value return nil case "CONTENT-LENGTH": numValue, err := strconv.ParseInt(value, 10, 64) if err != nil { return icserror.ICSERRSIPHeader } s.ContentLength = numValue return nil default: values := strings.Split(value, ";") // 헤더 값에 값을 없을 경우 초기화.. map이라서?? if len(s.Headers) == 0 { s.Headers = map[string][]string{} } for _, fieldValue := range values { s.Headers[name] = append(s.Headers[name], strings.TrimSpace(fieldValue)) } //fmt.Println("SIP~~~~~~~~~~~~~~~~~whoAU~~~~~~~~~~~~~~~~~" + value) } return nil } //implm interface Packeter func (s *SIP) GetPacketData(addr []*icsnet.IcsNetAddr, packet []byte) *icserror.IcsError { s.SrcAddr = addr[0] s.DstAddr = addr[1] return s.SipParser(packet) //fmt.Println("SIP GetPacketData()", s.SrcAddr, s.DstAddr) } func (s *SIP) GetCallID() string { return s.CallID }