aboutsummaryrefslogtreecommitdiff
path: root/src/gnunet/transport/connection.go
blob: 83372609eafe83484344553f5c587f42307ae686 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// This file is part of gnunet-go, a GNUnet-implementation in Golang.
// Copyright (C) 2019-2022 Bernd Fix  >Y<
//
// gnunet-go is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// gnunet-go is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: AGPL3.0-or-later

package transport

import (
	"context"
	"errors"
	"gnunet/message"
	"net"
)

// Error codes
var (
	ErrConnectionNotOpened   = errors.New("connection not opened")
	ErrConnectionInterrupted = errors.New("connection interrupted")
)

//----------------------------------------------------------------------

// Connection is a net.Conn for GNUnet message exchange (send/receive)
type Connection struct {
	conn net.Conn // associated connection
	buf  []byte   // read/write buffer
}

// NewConnection creates a new connection from an existing net.Conn
// This is usually used by clients to connect to a service.
func NewConnection(ctx context.Context, conn net.Conn) *Connection {
	return &Connection{
		conn: conn,
		buf:  make([]byte, 65536),
	}
}

// Close connection
func (s *Connection) Close() error {
	if s.conn != nil {
		rc := s.conn.Close()
		s.conn = nil
		return rc
	}
	return ErrConnectionNotOpened
}

// Send a GNUnet message over connection
func (s *Connection) Send(ctx context.Context, msg message.Message) error {
	return WriteMessage(ctx, s.conn, msg)
}

// Receive GNUnet messages from socket.
func (s *Connection) Receive(ctx context.Context) (message.Message, error) {
	return ReadMessage(ctx, s.conn, s.buf)
}

//----------------------------------------------------------------------

// ConnectionManager handles client connections on a net.Listener
type ConnectionManager struct {
	listener net.Listener // reference to listener object
}

// NewConnectionManager creates a new net.Listener connection manager.
// Incoming connections from clients are dispatched to a handler channel.
func NewConnectionManager(ctx context.Context, listener net.Listener, hdlr chan *Connection) (cs *ConnectionManager, err error) {
	// instantiate connection manager
	cs = &ConnectionManager{
		listener: listener,
	}
	// run watch dog for termination
	go func() {
		<-ctx.Done()
		cs.listener.Close()
	}()
	// run go routine to handle channel requests from clients
	go func() {
		for {
			conn, err := cs.listener.Accept()
			if err != nil {
				return
			}
			// handle connection
			c := &Connection{
				conn: conn,
				buf:  make([]byte, 65536),
			}
			hdlr <- c
		}
	}()
	return cs, nil
}

// Close a connection manager (= stop the server)
func (s *ConnectionManager) Close() (err error) {
	if s.listener != nil {
		err = s.listener.Close()
		s.listener = nil
	}
	return
}