mirror of
https://github.com/go-i2p/go-sam-go.git
synced 2025-07-01 05:21:59 -04:00
149 lines
4.0 KiB
Go
149 lines
4.0 KiB
Go
package datagram
|
|
|
|
import (
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/go-i2p/i2pkeys"
|
|
"github.com/samber/oops"
|
|
)
|
|
|
|
// ReadFrom reads a datagram from the connection
|
|
func (c *DatagramConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
|
c.mu.RLock()
|
|
if c.closed {
|
|
c.mu.RUnlock()
|
|
return 0, nil, oops.Errorf("connection is closed")
|
|
}
|
|
c.mu.RUnlock()
|
|
|
|
// Start receive loop if not already started
|
|
go c.reader.receiveLoop()
|
|
|
|
datagram, err := c.reader.ReceiveDatagram()
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
|
|
// Copy data to the provided buffer
|
|
n = copy(p, datagram.Data)
|
|
addr = &DatagramAddr{addr: datagram.Source}
|
|
|
|
return n, addr, nil
|
|
}
|
|
|
|
// WriteTo writes a datagram to the specified address
|
|
func (c *DatagramConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|
c.mu.RLock()
|
|
if c.closed {
|
|
c.mu.RUnlock()
|
|
return 0, oops.Errorf("connection is closed")
|
|
}
|
|
c.mu.RUnlock()
|
|
|
|
// Convert address to I2P address
|
|
i2pAddr, ok := addr.(*DatagramAddr)
|
|
if !ok {
|
|
return 0, oops.Errorf("address must be a DatagramAddr")
|
|
}
|
|
|
|
err = c.writer.SendDatagram(p, i2pAddr.addr)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return len(p), nil
|
|
}
|
|
|
|
// Close closes the datagram connection
|
|
func (c *DatagramConn) Close() error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
if c.closed {
|
|
return nil
|
|
}
|
|
|
|
logger := log.WithField("session_id", c.session.ID())
|
|
logger.Debug("Closing DatagramConn")
|
|
|
|
c.closed = true
|
|
|
|
// Close reader and writer - these are owned by this connection
|
|
if c.reader != nil {
|
|
c.reader.Close()
|
|
}
|
|
|
|
// DO NOT close the session - it's a shared resource that may be used by other connections
|
|
// The session should be closed by the code that created it, not by individual connections
|
|
// that use it. This follows the principle that the creator owns the resource.
|
|
|
|
logger.Debug("Successfully closed DatagramConn")
|
|
return nil
|
|
}
|
|
|
|
// LocalAddr returns the local address
|
|
func (c *DatagramConn) LocalAddr() net.Addr {
|
|
return &DatagramAddr{addr: c.session.Addr()}
|
|
}
|
|
|
|
// SetDeadline sets the read and write deadlines
|
|
func (c *DatagramConn) SetDeadline(t time.Time) error {
|
|
if err := c.SetReadDeadline(t); err != nil {
|
|
return err
|
|
}
|
|
return c.SetWriteDeadline(t)
|
|
}
|
|
|
|
// SetReadDeadline sets the deadline for future ReadFrom calls
|
|
func (c *DatagramConn) SetReadDeadline(t time.Time) error {
|
|
// For datagrams, we handle timeouts differently
|
|
// This is a placeholder implementation
|
|
return nil
|
|
}
|
|
|
|
// SetWriteDeadline sets the deadline for future WriteTo calls
|
|
func (c *DatagramConn) SetWriteDeadline(t time.Time) error {
|
|
// Calculate timeout duration
|
|
if !t.IsZero() {
|
|
timeout := time.Until(t)
|
|
c.writer.SetTimeout(timeout)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Read implements net.Conn by wrapping ReadFrom.
|
|
// It reads data into the provided byte slice and returns the number of bytes read.
|
|
// When reading, it also updates the remote address of the connection.
|
|
// Note: This is not a typical use case for datagrams, as they are connectionless.
|
|
// However, for compatibility with net.Conn, we implement it this way.
|
|
func (c *DatagramConn) Read(b []byte) (n int, err error) {
|
|
n, addr, err := c.ReadFrom(b)
|
|
c.remoteAddr = addr.(*i2pkeys.I2PAddr)
|
|
return n, err
|
|
}
|
|
|
|
// RemoteAddr returns the remote address of the connection.
|
|
// For datagram connections, this returns nil as there is no single remote address.
|
|
func (c *DatagramConn) RemoteAddr() net.Addr {
|
|
if c.remoteAddr != nil {
|
|
return &DatagramAddr{addr: *c.remoteAddr}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Write implements net.Conn by wrapping WriteTo.
|
|
// It writes data to the remote address and returns the number of bytes written.
|
|
// It uses the remote address set by the last Read operation.
|
|
// If no remote address is set, it returns an error.
|
|
// Note: This is not a typical use case for datagrams, as they are connectionless.
|
|
// However, for compatibility with net.Conn, we implement it this way.
|
|
func (c *DatagramConn) Write(b []byte) (n int, err error) {
|
|
if c.remoteAddr == nil {
|
|
return 0, oops.Errorf("no remote address set, use WriteTo or Read first")
|
|
}
|
|
|
|
addr := &DatagramAddr{addr: *c.remoteAddr}
|
|
return c.WriteTo(b, addr)
|
|
}
|