Skip to content
otfabricPublic

About

Pure Go MMS (ISO 9506) client/server library over RFC 1006. BER, ACSE, variable read/write, reports, files and journals for IEC 61850.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

60 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-mms

Go Go Reference License CI Codecov Release

A pure-Go implementation of the MMS (Manufacturing Message Specification) protocol, ISO 9506-1/2, designed as the base transport layer for industrial automation systems including IEC 61850.

Table of Contents

What is go-mms

  • Pure Go, no CGO — builds and cross-compiles with the standard toolchain.
  • Client and server — both sides of the protocol in one library.
  • Comprehensive MMS coverage for IEC 61850-oriented applications — variable access, named variable lists, file services, journal services, information reports, and more. Semaphore, Event, and Program Invocation services are outside scope.
  • Base layer for go-iec61850 — go-mms handles MMS; IEC 61850 abstractions live in a separate package.

Features

Category Services
Association Initiate, Conclude, Abort
Identity & Status Identify, Status
Variable Access Read (single, multi-variable, alternate access), Write (single, multi-variable, alternate access)
Named Variable Lists DefineNamedVariableList, GetNamedVariableListAttributes, DeleteNamedVariableList
Information Reports Send (server), receive (client), broadcast
File Services Open, Read, Close, Directory, Delete, Rename, ObtainFile, DownloadFile
Journal Services ReadJournal (time-range and start-after cursors)
Type Introspection GetVariableAccessAttributes
Object Enumeration GetNameList with automatic pagination

All services are supported on both client and server unless noted in COMPLIANCE.md.

Quick Start

Installation

go get github.com/otfabric/go-mms

Requires Go 1.26 or later.

Client

package main

import (
	"context"
	"fmt"
	"log"

	mms "github.com/otfabric/go-mms"
	"github.com/otfabric/go-mms/transport/iso"
)

func main() {
	ctx := context.Background()

	client, err := iso.Dial(ctx, "10.0.0.1:102",
		iso.WithClientDialOptions(mms.DialOptions{
			MMS: mms.MMSOptions{MaxPDUSize: 65000},
		}),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close(ctx)

	id, err := client.Identify(ctx)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Vendor: %s  Model: %s  Rev: %s\n", id.Vendor, id.Model, id.Revision)

	result, err := client.Read(ctx, mms.ReadRequest{
		DomainID: "MyDomain",
		ItemID:   "MyVariable",
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("Value:", result.Value)
}

Server

package main

import (
	"context"
	"errors"
	"log"

	mms "github.com/otfabric/go-mms"
	"github.com/otfabric/go-mms/transport/iso"
)

func main() {
	srv := mms.NewServer(mms.ServerOptions{
		MMS: mms.ServerMMSOptions{MaxPDUSize: 65000},
	})

	srv.HandleIdentify(func(_ context.Context, _ mms.IdentifyRequest) (*mms.ServerIdentity, error) {
		return &mms.ServerIdentity{Vendor: "Acme", Model: "Controller", Revision: "1.0"}, nil
	})

	srv.RegisterDomain("process")
	srv.RegisterVariable(mms.Variable{
		Name:     mms.ObjectName{Scope: mms.ObjectScopeDomain, Domain: "process", ItemID: "temperature"},
		TypeSpec: mms.TypeSpec{Type: mms.ValueTypeFloat, FormatWidth: 32, ExponentWidth: 8},
		Read: func(_ context.Context) (*mms.Value, error) {
			return mms.NewFloat(21.5), nil
		},
		Write: func(_ context.Context, v *mms.Value) error {
			f, ok := v.Float64()
			if !ok {
				return errors.New("expected float")
			}
			_ = f // store the value
			return nil
		},
	})

	ln, err := iso.Listen(":102")
	if err != nil {
		log.Fatal(err)
	}
	log.Fatal(srv.ListenAndServe(context.Background(), ln))
}

See examples/ for complete runnable examples.

Operations

  • Errors — every error is classified with sentinels and typed errors (ErrClosed, ErrInvokeTimeout, ErrInvalidArgument, *ServiceError, *RejectError, ...). Use errors.Is/errors.As, never the message. See ERRORS.md.
  • Timeouts — DialOptions.RequestTimeout bounds each confirmed request; ServerOptions.AssociationTimeout and iso.WithHandshakeTimeout bound connection setup. See TIMEOUT_AND_CLOSE.md and LIMITS.md.
  • Reconnect and retry — Client.Done()/Client.Err() report a lost association; iso.WithRetry(mms.DefaultRetryPolicy()) retries dialing, and mms.Retry wraps any operation in backoff with jitter.
  • Graceful shutdown — Server.Shutdown(ctx) stops accepting, lets in-flight requests finish and aborts the associations; ListenAndServe then returns mms.ErrServerClosed.
  • Metrics and logging — implement mms.Metrics (DialOptions.Metrics, ServerOptions.Metrics) to export request and connection events to Prometheus or OpenTelemetry; log/slog loggers via DialOptions.Logger, ServerOptions.Logger and iso.WithLogger. See OBSERVABILITY.md.
client, err := iso.Dial(ctx, "10.0.0.1:102",
	iso.WithRetry(mms.DefaultRetryPolicy()),
	iso.WithClientDialOptions(mms.DialOptions{
		RequestTimeout: 5 * time.Second,
		Metrics:        myMetrics, // implements mms.Metrics
	}),
)
if err != nil {
	log.Fatal(err)
}
go func() {
	<-client.Done()
	log.Println("association lost:", client.Err())
}()

// Server: stop gracefully on SIGTERM.
go func() {
	<-sigterm
	shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	_ = srv.Shutdown(shutdownCtx)
}()
if err := srv.ListenAndServe(ctx, ln); !errors.Is(err, mms.ErrServerClosed) {
	log.Fatal(err)
}

Architecture

go-mms implements the full ISO/OSI upper-layer stack required by MMS:

TPKT (RFC 1006)
 └─ COTP (ISO 8073)
     └─ Session (ISO 8327-1)
         └─ Presentation (ISO 8823-1)
             └─ ACSE (ISO 8650-1)
                 └─ MMS (ISO 9506-1/2)

The lower transport layers (TPKT and COTP) are provided by companion libraries go-tpkt and go-cotp. The transport/iso subpackage wires them together and exposes Dial (client) and Listen (server) entry points.

For custom or test transports, implement the Transport interface and pass it directly to NewClient or Server.Serve.

Out of Scope

The following are intentionally not part of go-mms:

  • IEC 61850 abstractions — data model, SCL, logical nodes, datasets. These belong in go-iec61850.
  • ASN.1 code generation — BER encoding is hand-written for performance and control.
  • Semaphore, Event, and Program Invocation services — rarely used MMS services not required for IEC 61850.
  • GOOSE, Sampled Values, GSE — non-MMS protocols defined in IEC 61850 parts 8-1 and 9-2.

Status

go-mms follows semantic versioning. The v1 API is stable; backward-incompatible public API changes are reserved for a future major release. Patch releases may correct protocol encoding or decoding defects without being considered breaking changes — a standards-correct wire fix can change observable behaviour while remaining API-compatible.

  • Well-tested: 1,000+ unit tests, 60+ end-to-end tests, 200+ negative tests, race/concurrency and chaos tests, 60 fuzz targets, 21 benchmarks.
  • Quality gates (CI quality job; coverage and the short fuzz pass are also part of make check): ≥ 90% statement coverage per package and in total (make coverage), a fuzz pass over every target (make fuzz-short; make fuzz for longer runs), and chaos tests under -race through a fault-injecting connection (make chaos). See PROGRESS.md.
  • Hardened: strict decoder validation, bounds checking on all PDU fields, resource limits on negotiated parameters.
  • Interop-verified: client and server behaviour tested bidirectionally against a pinned libiec61850 adapter; see INTEROP.md. Testing against physical IEDs has not yet been formally established.

Documentation

License

This project is licensed under the MIT License. See LICENSE.

About

Pure Go MMS (ISO 9506) client/server library over RFC 1006. BER, ACSE, variable read/write, reports, files and journals for IEC 61850.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages