package icspacketparser import ( "fmt" "regexp" "strconv" "strings" "gitlab.com/ics_cinnamon/voicegateway/icserror" "gitlab.com/ics_cinnamon/voicegateway/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 //response 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 ToRep 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 XAICall string Diversion string XAICallNumber string Media 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), "\r\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 { //parse SDP if len(strings.TrimSpace(strSipLine[line])) > 0 { if len(strings.TrimSpace(strSipLine[line])) == 0 { //fmt.Println("RRRR", line) return nil } splits := strings.SplitN(string(strings.TrimSpace(strSipLine[line])), "=", 2) if len(splits) < 2 { //fmt.Printf("RRRR22 strSipLine[line] : [%s]\n", strSipLine[line]) //fmt.Printf("RRRR22 strSipLine len: %d, line len: %d, byteArr: {%s}, SipLine:##### {%v}\n", //len(strSipLine), line, string(byteArr), strSipLine) break //return nil } name := strings.TrimSpace(splits[0]) value := strings.TrimSpace(splits[1]) //fmt.Println("@@@@", name, value) 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) { //fmt.Println("$$$$", sdpMedias) //fmt.Printf("MediaDescription: %s", sdpMedias[0].MediaDescription) 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 case "X-AICALL": s.XAICall = value case "DIVERSION": re := regexp.MustCompile(``) match := re.FindStringSubmatch(strings.TrimSpace(value)) if len(match) >= 2 { s.Diversion = match[1] } else { //에러 추가 필요 디버전에 대한 s.Diversion = "" return icserror.ICSERRSIPHeader } case "X-AINUMBER": s.XAICallNumber = value case "MEDIA": s.Media = value 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 } // representative func (s *SIP) SetTo(name string) { name1 := strings.SplitN(s.To, "@", 2) tmp := " 0 { agenturis := strings.SplitN(uris[0], ":", 3) //fmt.Println(">>>", uris, s.Method) return agenturis[1] } } return "" }