gocmpp

repository·master·Indexed 41 days ago

https://github.com/bigwhite/gocmpp

A Go implementation of the China Mobile Peer to Peer (CMPP) protocol supporting versions cmpp2.1 and cmpp3.0. It provides structures and methods for serializing and deserializing protocol packets, including connect, submit, deliver, fwd, active test, and terminate. The library supports both client and server-side implementations with built-in support for TCP connection management and packet unpacking.

Tokens
10.2K
Snippets
35
Records
43
Agent score
100%

What's inside gocmpp

  1. Understand the supported CMPP protocol features

    master

    gocmpp is a Go implementation of the China Mobile Peer to Peer (CMPP) protocol, supporting both client and server sides.

    Supported Protocol Versions

    • cmpp2.1
    • cmpp3.0

    Supported Packet Types

    The library supports the following CMPP packets:

    • connect
    • submit
    • deliver
    • fwd
    • active test
    • terminate

    Unsupported Packet Types

    The following packets are not supported and are not currently on the development roadmap:

    • query
    • cancel
    • route
  2. Learn how to use the gocmpp library

    master

    The most effective way to learn how to implement a CMPP client or server is to examine the provided examples in the examples/ directory:

    • Client implementation: Refer to examples/client/client.go to see how to use gocmpp from the client side.
    • Server implementation: Refer to examples/server/server.go to see how to construct a CMPP server using the library.
  3. Build gocmpp from source

    master

    gocmpp uses the Go vendor mechanism. You must use Go version 1.5 or later. To build the project and its examples, follow these steps:

    1. Enable the vendor experiment (for older Go versions).
    2. Navigate to the project directory.
    3. Run make to build the core and examples.

    Note: The build process includes compiling the server and client examples located in examples/server/server.go and examples/client/client.go.

    $ export GO15VENDOREXPERIMENT="1"
    $ cd $GOPATH/src/github.com/bigwhite/gocmpp
    $ make
  4. Manage CMPP connection states

    master

    The Conn struct tracks the lifecycle of the connection using the State type. You can manually update the state using SetState.

    Available States:

    • CONN_CLOSED: The connection is closed.
    • CONN_CONNECTED: The connection is established.
    • CONN_AUTHOK: The connection is authenticated.

    Note: Calling Close() on a *Conn will close the underlying net.Conn and set the state to CONN_CLOSED.

  5. Implement a CMMP server using ListenAndServe

    master

    To start a CMMP server, use the cmpp.ListenAndServe function. This function sets up a TCP listener, manages connection lifecycles, and handles active testing (heartbeats).

    Parameters

    • addr: The TCP address to listen on (e.g., ":8080").
    • typ: The CMMP protocol version (V20 or V30).
    • t: The interval between active tests (heartbeats).
    • n: The number of continuous active tests sent without a response before the connection is closed.
    • logWriter: An io.Writer for error logging (e.g., os.Stderr).
    • handlers: A variadic list of Handler implementations to process incoming packets. Handlers are executed in the order provided (middleware pattern).

    Handler Behavior

    Each handler's ServeCmpp method returns:

    1. bool: If true, the server continues to the next handler in the chain. If false, the chain stops.
    2. error: If non-nil, the server will send a response (if applicable) and then close the client connection.
    err := cmpp.ListenAndServe(
        ":8080",
        cmpp.V30,
        30*time.Second, // T: heartbeat interval
        3,              // N: max failed heartbeats
        os.Stderr,
        myHandler,
        middlewareHandler,
    )
  6. Use HandlerFunc to create middleware

    master

    The cmpp.HandlerFunc type allows you to implement a middleware pattern. Because ListenAndServe accepts multiple handlers, you can wrap logic (like authentication or logging) around your main business logic.

    In the chain, if a handler returns false, the subsequent handlers are not called. If a handler returns an error, the connection is closed.

    // A middleware that logs every request
    loggingMiddleware := cmpp.HandlerFunc(func(r *cmpp.Response, p *cmpp.Packet, l *log.Logger) (bool, error) {
        l.Printf("Received packet: %v", p.Packer)
        return true, nil // Continue to next handler
    })
    
    // The main business logic
    mainHandler := cmpp.HandlerFunc(func(r *cmpp.Response, p *cmpp.Packet, l *log.Logger) (bool, error) {
        // Handle specific CMMP logic here
        return false, nil // Stop the chain here
    })
    
    // Registering them
    // cmpp.ListenAndServe(..., loggingMiddleware, mainHandler)
  7. Send a CMPP packet using SendPkt

    master

    The SendPkt method packs a CMPP packet and writes it to the underlying connection. It requires a Packer interface implementation and a seqId.

    Parameters:

    • packet: An object implementing the Packer interface.
    • seqId: The sequence ID for the packet.

    Errors:

    • Returns ErrConnIsClosed if the connection state is CONN_CLOSED.
    err := cmppConn.SendPkt(myPacket, 12345)
    if err != nil {
        // handle error
    }
  8. Handle CMMP 3.x connection responses with Cmpp3ConnRspPkt

    master

    The Cmpp3ConnRspPkt struct is used for CMMP version 3.x connection responses. It differs from version 2.x primarily in the data type of the Status field (which is uint32 instead of uint8).

    Server-side usage (Packing): Initialize with Status, AuthSrc, Secret, and Version. Calling Pack(seqId uint32) generates the AuthIsmg using an MD5 hash of the status, AuthSrc, and Secret.

    Client-side usage (Unpacking): Calling Unpack(data []byte) will populate the SeqId, Status, AuthIsmg, and Version.

    // Server side example
    resp := &cmpp.Cmpp3ConnRspPkt{
        Status:   0,
        AuthSrc:  "auth_src",
        Secret:   "secret",
        Version:  cmpp.Type3,
    }
    bytes, err := resp.Pack(12345)
    
    // Client side example
    resp := &cmpp.Cmpp3ConnRspPkt{}
    err := resp.Unpack(incomingBytes)
  9. Define a custom CMMP Handler

    master

    You can implement the Handler interface to process incoming CMMP packets. Alternatively, you can use the HandlerFunc adapter to convert a standard function into a Handler.

    Handler Interface

    type Handler interface {
        ServeCmpp(r *Response, p *Packet, l *log.Logger) (bool, error)
    }

    HandlerFunc Adapter

    If you have a function with the signature func(*Response, *Packet, *log.Logger) (bool, error), you can cast it to cmpp.HandlerFunc to use it as a handler.

    Arguments

    • r (*Response): Contains the response packet to be sent back to the client. The SeqId in r.SeqId is used for the response.
    • p (*Packet): The incoming request packet.
    • l (*log.Logger): The server's error logger.

    Return Values

    • bool: Return true to allow the next handler in the chain to run. Return false to stop processing this packet.
    • error: Return a non-nil error to trigger a connection closure after the response is sent.
    // Using HandlerFunc for a simple handler
    myHandler := cmpp.HandlerFunc(func(r *cmpp.Response, p *cmpp.Packet, l *log.Logger) (bool, error) {
        // Process packet p
        // ...
        
        // Prepare a response if needed
        // r.Packer = &cmpp.Cmpp2SubmitRspPkt{SeqId: r.SeqId}
        
        return true, nil
    })
  10. Handle CMMP 2.x Submit Request and Response Packets

    master

    CMMP 2.x uses Cmpp2SubmitReqPkt for sending message requests and Cmpp2SubmitRspPkt for receiving responses.

    • Clients should initialize a Cmpp2SubmitReqPkt with the required fields and call .Pack(seqId) to generate the byte stream for transmission.
    • Servers should use .Unpack(data) to parse incoming byte streams into the struct, and .Pack(seqId) to send responses back to the client.

    Note: When packing a request, if PkTotal and PkNumber are both 0, the library automatically sets them to 1.

    // Client side: Packing a request
    req := &cmpp.Cmpp2SubmitReqPkt{
        MsgId:      12345,
        ServiceId:  "myservice",
        MsgSrc:     "mysrc",
        MsgContent: "hello world",
        // ... other fields
    }
    bytes, err := req.Pack(seqId)
    
    // Server side: Unpacking a request
    req := &cmpp.Cmpp2SubmitReqPkt{}
    err := req.Unpack(receivedBytes)
  11. Handle CMMP connection requests with CmppConnReqPkt

    master

    The CmppConnReqPkt struct represents a connection request for both CMMP version 2.x and 3.x.

    Client-side usage (Packing): You must initialize the struct with the correct SrcAddr, Secret, and Version. Calling Pack(seqId uint32) will automatically generate the AuthSrc (authenticator) using an MD5 hash of the source address, a padding buffer, the secret, and the timestamp.

    Server-side usage (Unpacking): You do not need to initialize the struct. Calling Unpack(data []byte) will populate the SeqId, SrcAddr, AuthSrc, Version, and Timestamp from the incoming byte stream.

    // Client side example
    req := &cmpp.CmppConnReqPkt{
        SrcAddr: "123456",
        Secret:  "your_secret",
        Version: cmpp.Type2, // Assuming Type2 is defined elsewhere
    }
    bytes, err := req.Pack(12345)
    
    // Server side example
    req := &cmpp.CmppConnReqPkt{}
    err := req.Unpack(incomingBytes)