mirror of
https://github.com/aler9/gortsplib
synced 2025-10-27 01:00:32 +08:00
move interleaved frames into dedicated struct
This commit is contained in:
@@ -12,15 +12,15 @@ func md5Hex(in string) string {
|
|||||||
return hex.EncodeToString(h.Sum(nil))
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthClientProvider struct {
|
type authClientProvider struct {
|
||||||
user string
|
user string
|
||||||
pass string
|
pass string
|
||||||
realm string
|
realm string
|
||||||
nonce string
|
nonce string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthClientProvider(user string, pass string, realm string, nonce string) *AuthClientProvider {
|
func newAuthClientProvider(user string, pass string, realm string, nonce string) *authClientProvider {
|
||||||
return &AuthClientProvider{
|
return &authClientProvider{
|
||||||
user: user,
|
user: user,
|
||||||
pass: pass,
|
pass: pass,
|
||||||
realm: realm,
|
realm: realm,
|
||||||
@@ -28,7 +28,7 @@ func NewAuthClientProvider(user string, pass string, realm string, nonce string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ap *AuthClientProvider) generateHeader(method string, path string) string {
|
func (ap *authClientProvider) generateHeader(method string, path string) string {
|
||||||
ha1 := md5Hex(ap.user + ":" + ap.realm + ":" + ap.pass)
|
ha1 := md5Hex(ap.user + ":" + ap.realm + ":" + ap.pass)
|
||||||
ha2 := md5Hex(method + ":" + path)
|
ha2 := md5Hex(method + ":" + path)
|
||||||
response := md5Hex(ha1 + ":" + ap.nonce + ":" + ha2)
|
response := md5Hex(ha1 + ":" + ap.nonce + ":" + ha2)
|
||||||
|
|||||||
118
conn.go
118
conn.go
@@ -1,118 +0,0 @@
|
|||||||
package gortsplib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Conn struct {
|
|
||||||
nconn net.Conn
|
|
||||||
writeBuf []byte
|
|
||||||
session string
|
|
||||||
clientCseqEnabled bool
|
|
||||||
clientCseq int
|
|
||||||
clientAuthProv *AuthClientProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConn(nconn net.Conn) *Conn {
|
|
||||||
return &Conn{
|
|
||||||
nconn: nconn,
|
|
||||||
writeBuf: make([]byte, 2048),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) NetConn() net.Conn {
|
|
||||||
return c.nconn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) SetSession(v string) {
|
|
||||||
c.session = v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) ClientEnableCseq() {
|
|
||||||
c.clientCseqEnabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) ClientSetCredentials(user string, pass string, realm string, nonce string) {
|
|
||||||
c.clientAuthProv = NewAuthClientProvider(user, pass, realm, nonce)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) ReadRequest() (*Request, error) {
|
|
||||||
return readRequest(c.nconn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) WriteRequest(req *Request) error {
|
|
||||||
if c.session != "" {
|
|
||||||
if req.Header == nil {
|
|
||||||
req.Header = make(Header)
|
|
||||||
}
|
|
||||||
req.Header["Session"] = []string{c.session}
|
|
||||||
}
|
|
||||||
if c.clientCseqEnabled {
|
|
||||||
if req.Header == nil {
|
|
||||||
req.Header = make(Header)
|
|
||||||
}
|
|
||||||
c.clientCseq += 1
|
|
||||||
req.Header["CSeq"] = []string{strconv.FormatInt(int64(c.clientCseq), 10)}
|
|
||||||
}
|
|
||||||
if c.clientAuthProv != nil {
|
|
||||||
if req.Header == nil {
|
|
||||||
req.Header = make(Header)
|
|
||||||
}
|
|
||||||
req.Header["Authorization"] = []string{c.clientAuthProv.generateHeader(req.Method, req.Url)}
|
|
||||||
}
|
|
||||||
return req.write(c.nconn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) ReadResponse() (*Response, error) {
|
|
||||||
return readResponse(c.nconn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) WriteResponse(res *Response) error {
|
|
||||||
return res.write(c.nconn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) ReadInterleavedFrame(buf []byte) (int, int, error) {
|
|
||||||
var header [4]byte
|
|
||||||
_, err := io.ReadFull(c.nconn, header[:])
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// connection terminated
|
|
||||||
if header[0] == 0x54 {
|
|
||||||
return 0, 0, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
if header[0] != 0x24 {
|
|
||||||
return 0, 0, fmt.Errorf("wrong magic byte (0x%.2x)", header[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
framelen := binary.BigEndian.Uint16(header[2:])
|
|
||||||
if int(framelen) > len(buf) {
|
|
||||||
return 0, 0, fmt.Errorf("frame length greater than buffer length")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.ReadFull(c.nconn, buf[:framelen])
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(header[1]), int(framelen), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) WriteInterleavedFrame(channel int, frame []byte) error {
|
|
||||||
c.writeBuf[0] = 0x24
|
|
||||||
c.writeBuf[1] = byte(channel)
|
|
||||||
binary.BigEndian.PutUint16(c.writeBuf[2:], uint16(len(frame)))
|
|
||||||
n := copy(c.writeBuf[4:], frame)
|
|
||||||
|
|
||||||
_, err := c.nconn.Write(c.writeBuf[:4+n])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
74
connclient.go
Normal file
74
connclient.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package gortsplib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConnClient struct {
|
||||||
|
nconn net.Conn
|
||||||
|
bw *bufio.Writer
|
||||||
|
session string
|
||||||
|
cseqEnabled bool
|
||||||
|
cseq int
|
||||||
|
authProv *authClientProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConnClient(nconn net.Conn) *ConnClient {
|
||||||
|
return &ConnClient{
|
||||||
|
nconn: nconn,
|
||||||
|
bw: bufio.NewWriterSize(nconn, _INTERLEAVED_FRAME_MAX_SIZE),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnClient) NetConn() net.Conn {
|
||||||
|
return c.nconn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnClient) SetSession(v string) {
|
||||||
|
c.session = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnClient) EnableCseq() {
|
||||||
|
c.cseqEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnClient) SetCredentials(user string, pass string, realm string, nonce string) {
|
||||||
|
c.authProv = newAuthClientProvider(user, pass, realm, nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnClient) WriteRequest(req *Request) error {
|
||||||
|
if c.session != "" {
|
||||||
|
if req.Header == nil {
|
||||||
|
req.Header = make(Header)
|
||||||
|
}
|
||||||
|
req.Header["Session"] = []string{c.session}
|
||||||
|
}
|
||||||
|
if c.cseqEnabled {
|
||||||
|
if req.Header == nil {
|
||||||
|
req.Header = make(Header)
|
||||||
|
}
|
||||||
|
c.cseq += 1
|
||||||
|
req.Header["CSeq"] = []string{strconv.FormatInt(int64(c.cseq), 10)}
|
||||||
|
}
|
||||||
|
if c.authProv != nil {
|
||||||
|
if req.Header == nil {
|
||||||
|
req.Header = make(Header)
|
||||||
|
}
|
||||||
|
req.Header["Authorization"] = []string{c.authProv.generateHeader(req.Method, req.Url)}
|
||||||
|
}
|
||||||
|
return req.write(c.nconn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnClient) ReadResponse() (*Response, error) {
|
||||||
|
return readResponse(c.nconn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnClient) ReadInterleavedFrame() (*InterleavedFrame, error) {
|
||||||
|
return readInterleavedFrame(c.nconn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnClient) WriteInterleavedFrame(frame *InterleavedFrame) error {
|
||||||
|
return frame.write(c.bw)
|
||||||
|
}
|
||||||
38
connserver.go
Normal file
38
connserver.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package gortsplib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConnServer struct {
|
||||||
|
nconn net.Conn
|
||||||
|
bw *bufio.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConnServer(nconn net.Conn) *ConnServer {
|
||||||
|
return &ConnServer{
|
||||||
|
nconn: nconn,
|
||||||
|
bw: bufio.NewWriterSize(nconn, _INTERLEAVED_FRAME_MAX_SIZE),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConnServer) NetConn() net.Conn {
|
||||||
|
return s.nconn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConnServer) ReadRequest() (*Request, error) {
|
||||||
|
return readRequest(s.nconn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConnServer) WriteResponse(res *Response) error {
|
||||||
|
return res.write(s.nconn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConnServer) ReadInterleavedFrame() (*InterleavedFrame, error) {
|
||||||
|
return readInterleavedFrame(s.nconn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConnServer) WriteInterleavedFrame(frame *InterleavedFrame) error {
|
||||||
|
return frame.write(s.bw)
|
||||||
|
}
|
||||||
73
interleavedframe.go
Normal file
73
interleavedframe.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package gortsplib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_INTERLEAVED_FRAME_MAX_SIZE = 2048
|
||||||
|
_INTERLEAVED_FRAME_MAX_CONTENT_SIZE = (_INTERLEAVED_FRAME_MAX_SIZE - 4)
|
||||||
|
)
|
||||||
|
|
||||||
|
type InterleavedFrame struct {
|
||||||
|
Channel uint8
|
||||||
|
Content []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func readInterleavedFrame(r io.Reader) (*InterleavedFrame, error) {
|
||||||
|
var header [4]byte
|
||||||
|
_, err := io.ReadFull(r, header[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// connection terminated
|
||||||
|
if header[0] == 0x54 {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
if header[0] != 0x24 {
|
||||||
|
return nil, fmt.Errorf("wrong magic byte (0x%.2x)", header[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
framelen := binary.BigEndian.Uint16(header[2:])
|
||||||
|
if int(framelen) > _INTERLEAVED_FRAME_MAX_SIZE {
|
||||||
|
return nil, fmt.Errorf("frame length greater than maximum allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
f := &InterleavedFrame{
|
||||||
|
Channel: header[1],
|
||||||
|
Content: make([]byte, framelen),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.ReadFull(r, f.Content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *InterleavedFrame) write(bw *bufio.Writer) error {
|
||||||
|
_, err := bw.Write([]byte{0x24, f.Channel})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(buf, uint16(len(f.Content)))
|
||||||
|
_, err = bw.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = bw.Write(f.Content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bw.Flush()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user