143 lines
3.9 KiB
Go
143 lines
3.9 KiB
Go
/*
|
|
* ============================================================================
|
|
* Projekt.....: rs2322tcp
|
|
* Datei.......: data_handler.go
|
|
* Copyright (C) 2026 Dieter Lang
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* Beschreibung:
|
|
* Verbindet eingehende TCP-Datenverbindungen eines Data-Listeners mit
|
|
* einem vom Server bereitgestellten seriellen Gerätekanal.
|
|
* ============================================================================
|
|
*/
|
|
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// SerialFactory
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SerialFactory creates a serial connection for one device.
|
|
//
|
|
// The concrete implementation is provided by the serial package later.
|
|
// Keeping the factory as a function type prevents the server package from
|
|
// depending directly on the concrete serial implementation.
|
|
type SerialFactory func() (io.ReadWriteCloser, error)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// DataHandler
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// DataHandler accepts TCP data connections and connects them to a serial
|
|
// device.
|
|
type DataHandler struct {
|
|
listener *DataListener
|
|
serialFactory SerialFactory
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Constructor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// NewDataHandler creates a new data handler.
|
|
//
|
|
// The listener provides the TCP endpoint. The serial factory is called for
|
|
// every accepted TCP connection.
|
|
func NewDataHandler(
|
|
listener *DataListener,
|
|
serialFactory SerialFactory,
|
|
) (*DataHandler, error) {
|
|
if listener == nil {
|
|
return nil, fmt.Errorf("data listener is nil")
|
|
}
|
|
|
|
if serialFactory == nil {
|
|
return nil, fmt.Errorf("serial factory is nil")
|
|
}
|
|
|
|
return &DataHandler{
|
|
listener: listener,
|
|
serialFactory: serialFactory,
|
|
}, nil
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Serve
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Serve waits for incoming TCP data connections.
|
|
//
|
|
// Every accepted connection gets its own serial connection and
|
|
// DataConnection. The handler runs independently for each client.
|
|
//
|
|
// Serve terminates when the listener is closed.
|
|
func (h *DataHandler) Serve() error {
|
|
if h == nil {
|
|
return fmt.Errorf("data handler is nil")
|
|
}
|
|
|
|
for {
|
|
tcpConn, err := h.listener.Accept()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
go h.handleConnection(tcpConn)
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Connection handling
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// handleConnection connects one accepted TCP connection to one serial
|
|
// connection.
|
|
func (h *DataHandler) handleConnection(tcpConn net.Conn) {
|
|
if tcpConn == nil {
|
|
return
|
|
}
|
|
|
|
serialConn, err := h.serialFactory()
|
|
if err != nil {
|
|
log.Printf("create serial connection: %v", err)
|
|
_ = tcpConn.Close()
|
|
return
|
|
}
|
|
|
|
dataConnection, err := NewDataConnection(
|
|
tcpConn,
|
|
serialConn,
|
|
)
|
|
if err != nil {
|
|
log.Printf("create data connection: %v", err)
|
|
|
|
_ = serialConn.Close()
|
|
_ = tcpConn.Close()
|
|
|
|
return
|
|
}
|
|
|
|
if err := dataConnection.Run(); err != nil {
|
|
log.Printf("data connection terminated: %v", err)
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Test support
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// HandleConnectionForTest handles one TCP connection using the configured
|
|
// serial factory.
|
|
//
|
|
// This method is intentionally provided for package-level tests without
|
|
// requiring a real TCP listener.
|
|
func (h *DataHandler) HandleConnectionForTest(tcpConn net.Conn) {
|
|
h.handleConnection(tcpConn)
|
|
}
|