fix: complete first version issue remediation
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -86,6 +87,7 @@ type DownstreamUplink struct {
|
||||
type downstreamSession struct {
|
||||
messageID string
|
||||
account string
|
||||
protocol string
|
||||
srcID string
|
||||
phoneNumber string
|
||||
gatewayMsgID uint64
|
||||
@@ -143,6 +145,7 @@ func (s Server) handleLogin(response *cmpp.Response, packet *cmpp.Packet, logger
|
||||
resp.AuthIsmg = string(authISMG[:])
|
||||
session := downstreamSession{
|
||||
account: strings.TrimSpace(defaultString(auth.Account, account)),
|
||||
protocol: cmppVersionName(req.Version),
|
||||
srcID: strings.TrimSpace(auth.Account),
|
||||
remoteIP: remoteIP(packet.Conn.Conn.RemoteAddr()),
|
||||
connectedAt: time.Now().UTC(),
|
||||
@@ -153,59 +156,150 @@ func (s Server) handleLogin(response *cmpp.Response, packet *cmpp.Packet, logger
|
||||
}
|
||||
rememberAccount(session)
|
||||
go s.flushPending(defaultString(auth.Account, account), logger)
|
||||
logger.Printf("cmpp inbound account=%s login ok remote=%s", account, packet.Conn.Conn.RemoteAddr())
|
||||
logger.Printf(
|
||||
"cmpp inbound event=login_accepted protocol=%s requested_version=0x%02x response_version=0x30 account=%s remote=%s",
|
||||
cmppVersionName(req.Version), req.Version, account, packet.Conn.Conn.RemoteAddr(),
|
||||
)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (s Server) handleSubmit(response *cmpp.Response, packet *cmpp.Packet, logger *log.Logger) (bool, error) {
|
||||
req, ok := packet.Packer.(*cmpp.Cmpp3SubmitReqPkt)
|
||||
req, ok := normalizeInboundSubmit(packet.Packer)
|
||||
if !ok {
|
||||
return true, nil
|
||||
}
|
||||
resp := response.Packer.(*cmpp.Cmpp3SubmitRspPkt)
|
||||
account := strings.TrimRight(req.MsgSrc, "\x00")
|
||||
account := strings.TrimRight(req.msgSrc, "\x00")
|
||||
phone := ""
|
||||
if len(req.DestTerminalId) > 0 {
|
||||
phone = strings.TrimRight(req.DestTerminalId[0], "\x00")
|
||||
if len(req.destTerminalIDs) > 0 {
|
||||
phone = strings.TrimRight(req.destTerminalIDs[0], "\x00")
|
||||
}
|
||||
content, err := decodeContent(req.MsgFmt, req.MsgContent)
|
||||
remote := packet.Conn.Conn.RemoteAddr()
|
||||
clientProtocol := inboundClientProtocol(account, packet.Conn, req.protocol)
|
||||
logger.Printf(
|
||||
"cmpp inbound event=submit_received protocol=%s packet_type=%s account=%s remote=%s seq=%d phone=%s src_id=%s msg_fmt=%d pk=%d/%d dest_count=%d content_bytes=%d",
|
||||
clientProtocol, req.protocol, account, remote, req.sequenceID, phone, strings.TrimSpace(req.srcID), req.msgFmt,
|
||||
req.pkNumber, req.pkTotal, len(req.destTerminalIDs), len(req.msgContent),
|
||||
)
|
||||
content, err := decodeContent(req.msgFmt, req.msgContent)
|
||||
if err != nil {
|
||||
logger.Printf("cmpp inbound decode submit failed account=%s seq=%d err=%v", account, req.SeqId, err)
|
||||
resp.Result = 9
|
||||
logger.Printf(
|
||||
"cmpp inbound event=submit_rejected protocol=%s packet_type=%s account=%s remote=%s seq=%d phone=%s result=9 stage=decode reason=%q",
|
||||
clientProtocol, req.protocol, account, remote, req.sequenceID, phone, err,
|
||||
)
|
||||
setInboundSubmitResponse(response.Packer, 0, 9)
|
||||
return false, nil
|
||||
}
|
||||
result, err := s.submit(packet.Conn.Conn.RemoteAddr(), submitRequest{
|
||||
contentHash := fmt.Sprintf("%x", md5.Sum([]byte(content)))
|
||||
startedAt := time.Now()
|
||||
result, err := s.submit(remote, submitRequest{
|
||||
Account: account,
|
||||
PhoneNumber: phone,
|
||||
Content: content,
|
||||
SrcID: req.SrcId,
|
||||
SrcID: req.srcID,
|
||||
DestID: phone,
|
||||
SequenceID: req.SeqId,
|
||||
RemoteIP: remoteIP(packet.Conn.Conn.RemoteAddr()),
|
||||
SequenceID: req.sequenceID,
|
||||
RemoteIP: remoteIP(remote),
|
||||
})
|
||||
if err != nil || !result.Accepted {
|
||||
logger.Printf("cmpp inbound submit rejected account=%s phone=%s seq=%d err=%v", account, phone, req.SeqId, err)
|
||||
resp.Result = 9
|
||||
reason := "api returned accepted=false"
|
||||
if err != nil {
|
||||
reason = err.Error()
|
||||
}
|
||||
logger.Printf(
|
||||
"cmpp inbound event=submit_rejected protocol=%s packet_type=%s account=%s remote=%s seq=%d phone=%s result=9 stage=business duration_ms=%d content_chars=%d content_hash=%s reason=%q",
|
||||
clientProtocol, req.protocol, account, remote, req.sequenceID, phone, time.Since(startedAt).Milliseconds(), len([]rune(content)), contentHash, reason,
|
||||
)
|
||||
setInboundSubmitResponse(response.Packer, 0, 9)
|
||||
return false, nil
|
||||
}
|
||||
resp.MsgId = messageIDFrom(result.MessageID, req.SeqId)
|
||||
resp.Result = 0
|
||||
gatewayMsgID := messageIDFrom(result.MessageID, req.sequenceID)
|
||||
setInboundSubmitResponse(response.Packer, gatewayMsgID, 0)
|
||||
rememberDownstream(downstreamSession{
|
||||
messageID: result.MessageID,
|
||||
account: account,
|
||||
srcID: strings.TrimSpace(req.SrcId),
|
||||
protocol: clientProtocol,
|
||||
srcID: strings.TrimSpace(req.srcID),
|
||||
phoneNumber: phone,
|
||||
gatewayMsgID: resp.MsgId,
|
||||
remoteIP: remoteIP(packet.Conn.Conn.RemoteAddr()),
|
||||
gatewayMsgID: gatewayMsgID,
|
||||
remoteIP: remoteIP(remote),
|
||||
connectedAt: time.Now().UTC(),
|
||||
conn: packet.Conn,
|
||||
mu: &sync.Mutex{},
|
||||
presence: s.PresenceStore,
|
||||
instanceID: s.gatewayInstanceID(),
|
||||
})
|
||||
logger.Printf(
|
||||
"cmpp inbound event=submit_accepted protocol=%s packet_type=%s account=%s remote=%s seq=%d phone=%s result=0 message_id=%s gateway_message_id=%d duration_ms=%d content_chars=%d content_hash=%s",
|
||||
clientProtocol, req.protocol, account, remote, req.sequenceID, phone, result.MessageID, gatewayMsgID, time.Since(startedAt).Milliseconds(), len([]rune(content)), contentHash,
|
||||
)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
type inboundSubmitPacket struct {
|
||||
protocol string
|
||||
pkTotal uint8
|
||||
pkNumber uint8
|
||||
msgFmt uint8
|
||||
msgSrc string
|
||||
srcID string
|
||||
destTerminalIDs []string
|
||||
msgContent string
|
||||
sequenceID uint32
|
||||
}
|
||||
|
||||
func normalizeInboundSubmit(packet any) (inboundSubmitPacket, bool) {
|
||||
switch req := packet.(type) {
|
||||
case *cmpp.Cmpp2SubmitReqPkt:
|
||||
return inboundSubmitPacket{
|
||||
protocol: "cmpp20", pkTotal: req.PkTotal, pkNumber: req.PkNumber, msgFmt: req.MsgFmt,
|
||||
msgSrc: req.MsgSrc, srcID: req.SrcId, destTerminalIDs: req.DestTerminalId,
|
||||
msgContent: req.MsgContent, sequenceID: req.SeqId,
|
||||
}, true
|
||||
case *cmpp.Cmpp3SubmitReqPkt:
|
||||
return inboundSubmitPacket{
|
||||
protocol: "cmpp30", pkTotal: req.PkTotal, pkNumber: req.PkNumber, msgFmt: req.MsgFmt,
|
||||
msgSrc: req.MsgSrc, srcID: req.SrcId, destTerminalIDs: req.DestTerminalId,
|
||||
msgContent: req.MsgContent, sequenceID: req.SeqId,
|
||||
}, true
|
||||
default:
|
||||
return inboundSubmitPacket{}, false
|
||||
}
|
||||
}
|
||||
|
||||
func setInboundSubmitResponse(packet any, messageID uint64, result uint32) {
|
||||
switch resp := packet.(type) {
|
||||
case *cmpp.Cmpp2SubmitRspPkt:
|
||||
resp.MsgId = messageID
|
||||
resp.Result = uint8(result)
|
||||
case *cmpp.Cmpp3SubmitRspPkt:
|
||||
resp.MsgId = messageID
|
||||
resp.Result = result
|
||||
}
|
||||
}
|
||||
|
||||
func inboundClientProtocol(account string, conn *cmpp.Conn, fallback string) string {
|
||||
downstreamRegistry.RLock()
|
||||
defer downstreamRegistry.RUnlock()
|
||||
session := downstreamRegistry.byAccount[account]
|
||||
if session != nil && session.conn == conn && session.protocol != "" {
|
||||
return session.protocol
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func cmppVersionName(version cmpp.Type) string {
|
||||
switch version {
|
||||
case cmpp.V20:
|
||||
return "cmpp20"
|
||||
case cmpp.V21:
|
||||
return "cmpp21"
|
||||
case cmpp.V30:
|
||||
return "cmpp30"
|
||||
default:
|
||||
return fmt.Sprintf("unknown_0x%02x", uint8(version))
|
||||
}
|
||||
}
|
||||
|
||||
func (s Server) authenticate(remote net.Addr, account string, authSource string, timestamp uint32) (authResponse, error) {
|
||||
payload := authRequest{
|
||||
Account: account,
|
||||
@@ -320,11 +414,22 @@ func (s Server) post(ctx context.Context, path string, payload any, result any)
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
responseBody, err := io.ReadAll(io.LimitReader(resp.Body, 64*1024))
|
||||
if err != nil {
|
||||
return fmt.Errorf("read api response: %w", err)
|
||||
}
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("api returned %s", resp.Status)
|
||||
detail := strings.TrimSpace(string(responseBody))
|
||||
if detail == "" {
|
||||
return fmt.Errorf("api returned %s", resp.Status)
|
||||
}
|
||||
return fmt.Errorf("api returned %s: %s", resp.Status, detail)
|
||||
}
|
||||
if result != nil {
|
||||
return json.NewDecoder(resp.Body).Decode(result)
|
||||
if len(responseBody) == 0 {
|
||||
return io.EOF
|
||||
}
|
||||
return json.Unmarshal(responseBody, result)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user