// successCEA sends a success answer indicating that the CER was successfuly // parsed and accepted by the server. func successCEA(sm *StateMachine, c diam.Conn, m *diam.Message, cer *smparser.CER) error { hostIP, _, err := net.SplitHostPort(c.LocalAddr().String()) if err != nil { return fmt.Errorf("failed to parse own ip %q: %s", c.LocalAddr(), err) } a := m.Answer(diam.Success) a.NewAVP(avp.OriginHost, avp.Mbit, 0, sm.cfg.OriginHost) a.NewAVP(avp.OriginRealm, avp.Mbit, 0, sm.cfg.OriginRealm) a.NewAVP(avp.HostIPAddress, avp.Mbit, 0, datatype.Address(net.ParseIP(hostIP))) a.NewAVP(avp.VendorID, avp.Mbit, 0, sm.cfg.VendorID) a.NewAVP(avp.ProductName, 0, 0, sm.cfg.ProductName) if cer.OriginStateID != nil { a.AddAVP(cer.OriginStateID) } if cer.AcctApplicationID != nil { for _, acct := range cer.AcctApplicationID { a.AddAVP(acct) } } if cer.AuthApplicationID != nil { for _, auth := range cer.AuthApplicationID { a.AddAVP(auth) } } if cer.VendorSpecificApplicationID != nil { for _, vs := range cer.VendorSpecificApplicationID { a.AddAVP(vs) } } if sm.cfg.FirmwareRevision != 0 { a.NewAVP(avp.FirmwareRevision, avp.Mbit, 0, sm.cfg.FirmwareRevision) } _, err = a.WriteTo(c) return err }
// errorCEA sends an error answer indicating that the CER failed due to // an unsupported (acct/auth) application, and includes the AVP that // caused the failure in the message. func errorCEA(sm *StateMachine, c diam.Conn, m *diam.Message, cer *smparser.CER, failedAVP *diam.AVP) error { hostIP, _, err := net.SplitHostPort(c.LocalAddr().String()) if err != nil { return fmt.Errorf("failed to parse own ip %q: %s", c.LocalAddr(), err) } var a *diam.Message if failedAVP == cer.InbandSecurityID { a = m.Answer(diam.NoCommonSecurity) } else { a = m.Answer(diam.NoCommonApplication) } a.Header.CommandFlags |= diam.ErrorFlag a.NewAVP(avp.OriginHost, avp.Mbit, 0, sm.cfg.OriginHost) a.NewAVP(avp.OriginRealm, avp.Mbit, 0, sm.cfg.OriginRealm) a.NewAVP(avp.HostIPAddress, avp.Mbit, 0, datatype.Address(net.ParseIP(hostIP))) a.NewAVP(avp.VendorID, avp.Mbit, 0, sm.cfg.VendorID) a.NewAVP(avp.ProductName, 0, 0, sm.cfg.ProductName) if cer.OriginStateID != nil { a.AddAVP(cer.OriginStateID) } a.NewAVP(avp.FailedAVP, avp.Mbit, 0, &diam.GroupedAVP{ AVP: []*diam.AVP{failedAVP}, }) if sm.cfg.FirmwareRevision != 0 { a.NewAVP(avp.FirmwareRevision, avp.Mbit, 0, sm.cfg.FirmwareRevision) } _, err = a.WriteTo(c) return err }
func (cli *Client) handshake(c diam.Conn) (diam.Conn, error) { ip, _, err := net.SplitHostPort(c.LocalAddr().String()) if err != nil { return nil, err } m := cli.makeCER(net.ParseIP(ip)) // Ignore CER, but not DWR. cli.Handler.mux.HandleFunc("CER", func(c diam.Conn, m *diam.Message) {}) // Handle CEA and DWA. errc := make(chan error) dwac := make(chan struct{}) cli.Handler.mux.Handle("CEA", handleCEA(cli.Handler, errc)) cli.Handler.mux.Handle("DWA", handshakeOK(handleDWA(cli.Handler, dwac))) for i := 0; i < (int(cli.MaxRetransmits) + 1); i++ { _, err := m.WriteTo(c) if err != nil { return nil, err } select { case err := <-errc: // Wait for CEA. if err != nil { close(errc) return nil, err } if cli.EnableWatchdog { go cli.watchdog(c, dwac) } return c, nil case <-time.After(cli.RetransmitInterval): } } c.Close() return nil, ErrHandshakeTimeout }