Issue #4: add and use telnetRead() function
This commit is contained in:
1 parent
f01cf72d6d
commit
cfa06ec4bc
3 files changed
+78
-5
No files matched your search
@@ -35,7 +35,6 @@ I would like to add:
|
||||
Known Problems
|
||||
--------------
|
||||
|
||||
- The telnet data is not checked for the special telnet byte value, 0xFF, which requires escaping while sending and unescaping while receiving data. If your 3270 data streams contain an FF character, things will probably break. However...I don't think 0xFF should ever appear in the datastream, so we're probably okay.
|
||||
- The telnet negotiation does not check for any errors or for any responses from the client. We just assume it goes well and we're actually talking to a tn3270 client.
|
||||
|
||||
License
|
||||
|
||||
+4
-4
@@ -99,7 +99,7 @@ func readResponse(c net.Conn, fm fieldmap) (Response, error) {
|
||||
func readAID(c net.Conn) (AID, error) {
|
||||
buf := make([]byte, 1)
|
||||
for {
|
||||
_, err := c.Read(buf)
|
||||
_, err := telnetRead(c, buf)
|
||||
if err != nil {
|
||||
return AIDNone, err
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func readPosition(c net.Conn) (row, col, addr int, err error) {
|
||||
|
||||
// Read two bytes
|
||||
for i := 0; i < 2; i++ {
|
||||
if _, err := c.Read(buf); err != nil {
|
||||
if _, err := telnetRead(c, buf); err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
raw[i] = buf[0]
|
||||
@@ -150,7 +150,7 @@ func readFields(c net.Conn, fm fieldmap) (map[string]string, error) {
|
||||
// consume bytes until we get 0xffef
|
||||
for {
|
||||
// Read a byte
|
||||
if _, err = c.Read(buf); err != nil {
|
||||
if _, err = telnetRead(c, buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ func readFields(c net.Conn, fm fieldmap) (map[string]string, error) {
|
||||
}
|
||||
|
||||
// consume the next byte, which is probably 0xef
|
||||
if _, err = c.Read(buf); err != nil {
|
||||
if _, err = telnetRead(c, buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return values, nil
|
||||
|
||||
@@ -68,3 +68,77 @@ func flushConnection(conn net.Conn, timeout time.Duration) error {
|
||||
timeout = time.Second / 2
|
||||
}
|
||||
}
|
||||
|
||||
// telnetRead behaves similarly to conn.Read, except it filters out telnet
|
||||
// commands. A single call to telnetRead() may perform multiple calls to
|
||||
// c.Read() if awaiting completion of a command, or to ensure we do not return
|
||||
// zero bytes in a non-error condition.
|
||||
func telnetRead(c net.Conn, p []byte) (n int, err error) {
|
||||
const (
|
||||
normal = iota
|
||||
command
|
||||
subneg
|
||||
)
|
||||
|
||||
// Not the most efficient, but for now to keep the code easier we'll just
|
||||
// read 1 byte at a time from the connection.
|
||||
b := make([]byte, 1)
|
||||
state := normal
|
||||
|
||||
for n < len(p) {
|
||||
bn, berr := c.Read(b)
|
||||
|
||||
// When there are no bytes to process and we received an error, we
|
||||
// are done no matter what state we're in. Any non-command bytes will
|
||||
// already be in p, so we return.
|
||||
if bn == 0 && berr != nil {
|
||||
return n, berr
|
||||
}
|
||||
|
||||
// If we received 0 bytes but no error, we'll just read again.
|
||||
if bn == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// We got a byte! Let's progress through our state machine.
|
||||
switch state {
|
||||
case normal:
|
||||
if b[0] == iac {
|
||||
state = command
|
||||
debugf("entering telnet command state\n")
|
||||
} else {
|
||||
p[n] = b[0]
|
||||
n++
|
||||
}
|
||||
case command:
|
||||
if b[0] == 0xff {
|
||||
p[n] = 0xff
|
||||
n++
|
||||
state = normal
|
||||
debugf("leaving telnet command state; was an escaped 0xff\n")
|
||||
} else if b[0] == sb {
|
||||
state = subneg
|
||||
debugf("entering telnet command subnegotiation state\n")
|
||||
} else {
|
||||
state = normal
|
||||
debugf("leaving telnet command state; command was %02x\n",
|
||||
b[0])
|
||||
}
|
||||
case subneg:
|
||||
if b[0] == se {
|
||||
state = normal
|
||||
debugf("leaving telnet command subnegotiation state\n")
|
||||
} else {
|
||||
// remain in subnegotiation consuming bytes until we get se
|
||||
debugf("consumed telnet subnegotiation byte: %02x\n", b[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Now we handle any errors that returned partial data
|
||||
if berr != nil {
|
||||
return n, berr
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
Reference in new issue
Block a user