2023-02-20 11:55:50 +01:00
|
|
|
//go:build !js || !wasm
|
|
|
|
|
|
|
|
package zocket
|
2020-03-11 16:07:14 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"time"
|
2024-08-31 13:08:44 +02:00
|
|
|
"udico.de/util/log"
|
2020-03-11 16:07:14 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// ServerConnection is the serverside part of the ws abstraction
|
|
|
|
type ServerConnection struct {
|
2023-02-20 11:55:50 +01:00
|
|
|
conn net.Conn // The underlying REAL connection.
|
2020-03-11 16:07:14 +01:00
|
|
|
buffered []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read gets some bytes from a ws frame. Blocks.
|
|
|
|
func (c ServerConnection) Read(b []byte) (int, error) {
|
|
|
|
if len(c.buffered) > 0 {
|
|
|
|
for i, _ := range b {
|
|
|
|
if i >= len(c.buffered) {
|
|
|
|
c.buffered = nil
|
|
|
|
return i, nil
|
|
|
|
}
|
|
|
|
b[i] = c.buffered[i]
|
|
|
|
}
|
|
|
|
if len(c.buffered) > len(b) {
|
|
|
|
c.buffered = c.buffered[len(b):]
|
|
|
|
}
|
|
|
|
return len(b), nil
|
|
|
|
}
|
2023-02-20 11:55:50 +01:00
|
|
|
buf := &bytes.Buffer{} //
|
|
|
|
datloop:
|
2020-03-11 16:07:14 +01:00
|
|
|
for {
|
|
|
|
tFrame, err := ReadFrame(c.conn)
|
|
|
|
if err != nil {
|
2023-02-20 11:55:50 +01:00
|
|
|
return 0, err
|
|
|
|
}
|
2020-03-11 16:07:14 +01:00
|
|
|
switch tFrame.Opcode {
|
|
|
|
case FrameType_Ping:
|
|
|
|
// send pong
|
|
|
|
tFrame.Opcode = FrameType_Pong
|
|
|
|
tFrame.WriteTo(c.conn)
|
|
|
|
case FrameType_Pong:
|
|
|
|
// decide
|
|
|
|
|
|
|
|
case FrameType_Close:
|
|
|
|
c.Close()
|
|
|
|
return 0, errors.New(fmt.Sprintf("connection closed: %v", tFrame.Payload[:]))
|
|
|
|
case FrameType_Binary:
|
|
|
|
buf.Write(tFrame.Payload)
|
|
|
|
if tFrame.Fin {
|
|
|
|
break datloop
|
|
|
|
}
|
|
|
|
default:
|
2024-08-31 13:08:44 +02:00
|
|
|
log.ERROR.To(logger).Msg("uhandled frame type: %v", tFrame.Opcode)
|
2020-03-11 16:07:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
bytes := buf.Bytes()
|
|
|
|
for i, _ := range b {
|
|
|
|
if i >= len(bytes) {
|
|
|
|
return i, nil
|
|
|
|
}
|
|
|
|
b[i] = bytes[i]
|
|
|
|
}
|
|
|
|
if len(bytes) > len(b) {
|
|
|
|
c.buffered = bytes[len(b):]
|
|
|
|
}
|
|
|
|
return len(b), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write puts some bytes packed into websocket frames on the wire.
|
|
|
|
func (c ServerConnection) Write(b []byte) (int, error) {
|
|
|
|
tFrame := &Frame{
|
|
|
|
Fin: true,
|
|
|
|
Opcode: FrameType_Binary,
|
|
|
|
Masked: false,
|
|
|
|
Mask: [4]byte{},
|
|
|
|
Len: uint64(len(b)),
|
|
|
|
Payload: b,
|
|
|
|
}
|
|
|
|
err := tFrame.WriteTo(c.conn)
|
|
|
|
return len(b), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close terminates the connection nicely.
|
|
|
|
func (c ServerConnection) Close() error {
|
2024-08-31 13:08:44 +02:00
|
|
|
log.TRACE.To(logger).Msg("serverconn_close %v", c)
|
2020-03-11 16:07:14 +01:00
|
|
|
//debug.PrintStack()
|
|
|
|
tFrame := &Frame{
|
|
|
|
Fin: true,
|
|
|
|
Opcode: FrameType_Close,
|
|
|
|
Masked: false,
|
|
|
|
Mask: [4]byte{},
|
|
|
|
Len: 0,
|
|
|
|
Payload: nil,
|
|
|
|
}
|
|
|
|
_ = tFrame.WriteTo(c.conn)
|
|
|
|
return c.conn.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c ServerConnection) LocalAddr() net.Addr {
|
|
|
|
return c.conn.LocalAddr()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c ServerConnection) RemoteAddr() net.Addr {
|
|
|
|
return c.conn.RemoteAddr()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c ServerConnection) SetDeadline(t time.Time) error {
|
|
|
|
return c.conn.SetDeadline(t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c ServerConnection) SetReadDeadline(t time.Time) error {
|
|
|
|
return c.conn.SetReadDeadline(t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c ServerConnection) SetWriteDeadline(t time.Time) error {
|
|
|
|
return c.conn.SetWriteDeadline(t)
|
|
|
|
}
|