File: dial.go

package info (click to toggle)
golang-github-harenber-ptc-go 2.2.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 116 kB
  • sloc: makefile: 5
file content (170 lines) | stat: -rwxr-xr-x 3,802 bytes parent folder | download | duplicates (2)
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package pactor

import (
	"fmt"
	"io"
	"net"
	"runtime"
	"strconv"
	"time"

	"github.com/la5nta/wl2k-go/transport"
)

// DialURL dials pactor:// URLs
//
// BLOCK until connection is established or timeoud occured
func (p *Modem) DialURL(url *transport.URL) (net.Conn, error) {
	if url.Scheme != "pactor" {
		return nil, transport.ErrUnsupportedScheme
	}

	if err := p.call(url.Target); err != nil {
		return nil, err
	}

	return p, nil
}

// Read bytes from the Software receive buffer. The receive thread takes care of
// reading them from the pactor modem
//
// BLOCK until receive buffer has any data!
func (p *Modem) Read(d []byte) (int, error) {
	p.mux.read.Lock()
	defer p.mux.read.Unlock()

	if p.state != Connected {
		return 0, fmt.Errorf("Read from closed connection")
	}

	if len(d) == 0 {
		return 0, nil
	}

	data, ok := <-p.recvBuf
	if !ok {
		return 0, io.EOF
	}

	if len(data) > len(d) {
		panic("too large") //TODO: Handle
	}

	for i, b := range data {
		d[i] = byte(b)
	}

	return len(data), nil
}

// Write bytes to the software send buffer. The send thread will take care of
// fowarding them to the pactor modem
//
// BLOCK if send buffer is full! Remains as soon as there is space left in the
// send buffer
func (p *Modem) Write(d []byte) (int, error) {
	p.mux.write.Lock()
	defer p.mux.write.Unlock()

	if p.state != Connected {
		return 0, fmt.Errorf("Read from closed connection")
	}

	for _, b := range d {
		select {
		case <-p.flags.closeWriting:
			return 0, fmt.Errorf("Writing on closed connection")
		case p.sendBuf <- b:
		}

		p.mux.bufLen.Lock()
		p.sendBufLen++
		p.mux.bufLen.Unlock()
	}

	return len(d), nil
}

// Flush waits for the last frames to be transmitted.
//
// Will throw error if remaining frames could not bet sent within 120s
func (p *Modem) Flush() (err error) {
	if p.state != Connected {
		return fmt.Errorf("Flush a closed connection")
	}

	writeDebug("Flush called", 2)
	if err = p.waitTransmissionFinish(120 * time.Second); err != nil {
		writeDebug(err.Error(), 2)
	}
	return
}

// Close closes the current connection.
//
// Will abort ("dirty disconnect") after 60 seconds if normal "disconnect" have
// not succeeded yet.
func (p *Modem) Close() error {
	if p.flags.closed {
		return nil
	}

	p.mux.close.Lock()

	_, file, no, ok := runtime.Caller(1)
	if ok {
		writeDebug("Close called from "+file+"#"+strconv.Itoa(no), 2)
	} else {
		writeDebug("Close called", 2)
	}

	if p.flags.closeCalled != true {
		defer p.mux.close.Unlock()

		p.flags.closeCalled = true

		if p.state == Connected {
			// Connected to remote, try to send remaining frames and disconnect
			// gracefully
			defer p.close()

			// Wait for remaining data to be transmitted and acknowledged
			if err := p.waitTransmissionFinish(90 * time.Second); err != nil {
				writeDebug(err.Error(), 2)
			}

			p.disconnect()

			// Wait for disconnect command to be transmitted and acknowledged
			if err := p.waitTransmissionFinish(30 * time.Second); err != nil {
				writeDebug(err.Error(), 2)
			}
		} else {
			// Link Setup (connection) not yet successful, force disconnect
			p.forceDisconnect()
		}

		// Wait for the modem to change state from connected to disconnected
		select {
		case <-p.flags.disconnected:
			writeDebug("Disconnect successful", 1)
			return nil
		case <-time.After(60 * time.Second):
			p.forceDisconnect()
			return fmt.Errorf("Disconnect timed out")
		}
	}

	writeDebug("Should never reach this...", 1)
	return nil
}

// TxBufferLen returns the number of bytes in the out buffer queue.
//
func (p *Modem) TxBufferLen() int {
	p.mux.bufLen.Lock()
	defer p.mux.bufLen.Unlock()
	writeDebug("TxBufferLen called ("+strconv.Itoa(p.sendBufLen)+" bytes remaining in buffer)", 2)
	return p.sendBufLen + (p.getNumFramesNotTransmitted() * MaxSendData)
}