func sendHMR(c diam.Conn, cfg *sm.Settings) error { // Get this client's metadata from the connection object, // which is set by the state machine after the handshake. // It contains the peer's Origin-Host and Realm from the // CER/CEA handshake. We use it to populate the AVPs below. meta, ok := smpeer.FromContext(c.Context()) if !ok { return errors.New("peer metadata unavailable") } sid := "session;" + strconv.Itoa(int(rand.Uint32())) m := diam.NewRequest(helloMessage, helloApplication, nil) m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(sid)) m.NewAVP(avp.OriginHost, avp.Mbit, 0, cfg.OriginHost) m.NewAVP(avp.OriginRealm, avp.Mbit, 0, cfg.OriginRealm) m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, meta.OriginRealm) m.NewAVP(avp.DestinationHost, avp.Mbit, 0, meta.OriginHost) m.NewAVP(avp.UserName, avp.Mbit, 0, datatype.UTF8String("foobar")) log.Printf("Sending HMR to %s\n%s", c.RemoteAddr(), m) _, err := m.WriteTo(c) return err }
// GetBridge returns the Bridge object for a given client, if it exists. // Otherwise GetBridge connects to the upstream server and set up the // bridge with the client, returning the newly created Bridge object. func GetBridge(c diam.Conn) *Bridge { liveMu.RLock() if b, ok := liveBridge[c.RemoteAddr().String()]; ok { liveMu.RUnlock() return b } liveMu.RUnlock() liveMu.Lock() defer liveMu.Unlock() b := &Bridge{ Client: make(chan *diam.Message), Server: make(chan *diam.Message), } liveBridge[c.RemoteAddr().String()] = b // Prepare for the upstream connection. mux := diam.NewServeMux() mux.HandleFunc("ALL", func(c diam.Conn, m *diam.Message) { // Forward incoming messages to the client. b.Client <- m }) // Connect to upstream server. s, err := diam.Dial(upstreamAddr, mux, nil) if err != nil { return nil } log.Printf("Creating bridge from %s to %s", c.RemoteAddr().String(), s.RemoteAddr().String()) go Pump(c, s, b.Client, b.Server) go Pump(s, c, b.Server, b.Client) return b }
func (self *DiameterAgent) handleALL(c diam.Conn, m *diam.Message) { utils.Logger.Warning(fmt.Sprintf("<DiameterAgent> Received unexpected message from %s:\n%s", c.RemoteAddr(), m)) }
func (self *DiameterAgent) handleCCR(c diam.Conn, m *diam.Message) { ccr, err := NewCCRFromDiameterMessage(m, self.cgrCfg.DiameterAgentCfg().DebitInterval) if err != nil { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Unmarshaling message: %s, error: %s", m, err)) return } var cca *CCA // For now we simply overload in loop, maybe we will find some other use of this for _, reqProcessor := range self.cgrCfg.DiameterAgentCfg().RequestProcessors { cca = self.processCCR(ccr, reqProcessor) if cca != nil && !reqProcessor.ContinueOnSuccess { break } } if cca == nil { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> No request processor enabled for CCR: %s, ignoring request", ccr.diamMessage)) return } if _, err := cca.AsDiameterMessage().WriteTo(c); err != nil { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Failed to write message to %s: %s\n%s\n", c.RemoteAddr(), err, cca.AsDiameterMessage())) return } }
func (self *DiameterAgent) handlerCCR(c diam.Conn, m *diam.Message) { ccr, err := NewCCRFromDiameterMessage(m, self.cgrCfg.DiameterAgentCfg().DebitInterval) if err != nil { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Unmarshaling message: %s, error: %s", m, err)) return } cca := NewBareCCAFromCCR(ccr, self.cgrCfg.DiameterAgentCfg().OriginHost, self.cgrCfg.DiameterAgentCfg().OriginRealm) var processed, lclProcessed bool processorVars := make(map[string]string) // Shared between processors for _, reqProcessor := range self.cgrCfg.DiameterAgentCfg().RequestProcessors { lclProcessed, err = self.processCCR(ccr, reqProcessor, processorVars, cca) if lclProcessed { // Process local so we don't overwrite globally processed = lclProcessed } if err != nil || (lclProcessed && !reqProcessor.ContinueOnSuccess) { break } } if err != nil && err != ErrDiameterRatingFailed { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> CCA SetProcessorAVPs for message: %+v, error: %s", ccr.diamMessage, err)) return } else if !processed { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> No request processor enabled for CCR: %s, ignoring request", ccr.diamMessage)) return } self.connMux.Lock() defer self.connMux.Unlock() if _, err := cca.AsDiameterMessage().WriteTo(c); err != nil { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Failed to write message to %s: %s\n%s\n", c.RemoteAddr(), err, cca.AsDiameterMessage())) return } }
// Pump messages from one side to the other. func Pump(src, dst diam.Conn, srcChan, dstChan chan *diam.Message) { for { select { case m := <-srcChan: if m == nil { src.Close() return } log.Printf( "Message from %s to %s\n%s", src.RemoteAddr().String(), dst.RemoteAddr().String(), m, ) if _, err := m.WriteTo(src); err != nil { src.Close() // triggers the case below } case <-src.(diam.CloseNotifier).CloseNotify(): liveMu.Lock() defer liveMu.Unlock() if _, ok := liveBridge[src.RemoteAddr().String()]; ok { delete(liveBridge, src.RemoteAddr().String()) log.Printf( "Destroying bridge from %s to %s", src.RemoteAddr().String(), dst.RemoteAddr().String(), ) } else { delete(liveBridge, dst.RemoteAddr().String()) log.Printf( "Destroying bridge from %s to %s", dst.RemoteAddr().String(), src.RemoteAddr().String(), ) } src.Close() dstChan <- nil return } } }
func handleALL(c diam.Conn, m *diam.Message) { log.Printf("Received unexpected message from %s:\n%s", c.RemoteAddr(), m) }