Session now Conn, init() moved into Dial(), and connectStream() merged into connect().

This commit is contained in:
scruzin 2019-01-19 13:12:24 +10:30
parent a73c73617a
commit 998d41c96f
1 changed files with 109 additions and 139 deletions

View File

@ -162,79 +162,49 @@ var (
errUnimplemented = errors.New("rtmp: unimplemented feature")
)
// init initialises the Session link
func (s *Session) init() (err error) {
s.link.protocol, s.link.host, s.link.port, s.link.app, s.link.playpath, err = parseURL(s.url)
if err != nil {
return err
}
if s.link.app == "" {
return errInvalidURL
}
if s.link.port == 0 {
switch {
case (s.link.protocol & featureSSL) != 0:
s.link.port = 433
s.log(FatalLevel, pkg+"SSL not supported")
case (s.link.protocol & featureHTTP) != 0:
s.link.port = 80
default:
s.link.port = 1935
}
}
s.link.url = rtmpProtocolStrings[s.link.protocol] + "://" + s.link.host + ":" + strconv.Itoa(int(s.link.port)) + "/" + s.link.app
s.link.protocol |= featureWrite
return nil
}
// connect establishes an RTMP connection.
func connect(s *Session) error {
addr, err := net.ResolveTCPAddr("tcp4", s.link.host+":"+strconv.Itoa(int(s.link.port)))
func connect(c *Conn) error {
addr, err := net.ResolveTCPAddr("tcp4", c.link.host+":"+strconv.Itoa(int(c.link.port)))
if err != nil {
return err
}
s.link.conn, err = net.DialTCP("tcp4", nil, addr)
c.link.conn, err = net.DialTCP("tcp4", nil, addr)
if err != nil {
s.log(WarnLevel, pkg+"dial failed", "error", err.Error())
c.log(WarnLevel, pkg+"dial failed", "error", err.Error())
return err
}
s.log(DebugLevel, pkg+"connected")
err = handshake(s)
c.log(DebugLevel, pkg+"connected")
err = handshake(c)
if err != nil {
s.log(WarnLevel, pkg+"handshake failed", "error", err.Error())
c.log(WarnLevel, pkg+"handshake failed", "error", err.Error())
return err
}
s.log(DebugLevel, pkg+"handshaked")
err = sendConnectPacket(s)
c.log(DebugLevel, pkg+"handshaked")
err = sendConnectPacket(c)
if err != nil {
s.log(WarnLevel, pkg+"sendConnect failed", "error", err.Error())
c.log(WarnLevel, pkg+"sendConnect failed", "error", err.Error())
return err
}
return nil
}
// connectStream reads a packet and handles it
func connectStream(s *Session) error {
var err error
for !s.isPlaying {
c.log(DebugLevel, pkg+"negotiating")
for !c.isPlaying {
pkt := packet{}
err = pkt.readFrom(s)
err = pkt.readFrom(c)
if err != nil {
break
}
switch pkt.packetType {
case packetTypeAudio, packetTypeVideo, packetTypeInfo:
s.log(WarnLevel, pkg+"got packet before play; ignoring", "type", pkt.packetType)
c.log(WarnLevel, pkg+"got packet before play; ignoring", "type", pkt.packetType)
default:
err = handlePacket(s, &pkt)
err = handlePacket(c, &pkt)
if err != nil {
break
}
}
}
if !s.isPlaying {
if !c.isPlaying {
return err
}
return nil
@ -242,50 +212,50 @@ func connectStream(s *Session) error {
// handlePacket handles a packet that the client has received.
// NB: Unsupported packet types are logged fatally.
func handlePacket(s *Session, pkt *packet) error {
func handlePacket(c *Conn, pkt *packet) error {
if pkt.bodySize < 4 {
return errInvalidBody
}
switch pkt.packetType {
case packetTypeChunkSize:
s.inChunkSize = amf.DecodeInt32(pkt.body[:4])
s.log(DebugLevel, pkg+"set inChunkSize", "size", int(s.inChunkSize))
c.inChunkSize = amf.DecodeInt32(pkt.body[:4])
c.log(DebugLevel, pkg+"set inChunkSize", "size", int(c.inChunkSize))
case packetTypeBytesReadReport:
s.log(DebugLevel, pkg+"received packetTypeBytesReadReport")
c.log(DebugLevel, pkg+"received packetTypeBytesReadReport")
case packetTypeServerBW:
s.serverBW = amf.DecodeInt32(pkt.body[:4])
s.log(DebugLevel, pkg+"set serverBW", "size", int(s.serverBW))
c.serverBW = amf.DecodeInt32(pkt.body[:4])
c.log(DebugLevel, pkg+"set serverBW", "size", int(c.serverBW))
case packetTypeClientBW:
s.clientBW = amf.DecodeInt32(pkt.body[:4])
s.log(DebugLevel, pkg+"set clientBW", "size", int(s.clientBW))
c.clientBW = amf.DecodeInt32(pkt.body[:4])
c.log(DebugLevel, pkg+"set clientBW", "size", int(c.clientBW))
if pkt.bodySize > 4 {
s.clientBW2 = pkt.body[4]
s.log(DebugLevel, pkg+"set clientBW2", "size", int(s.clientBW2))
c.clientBW2 = pkt.body[4]
c.log(DebugLevel, pkg+"set clientBW2", "size", int(c.clientBW2))
} else {
s.clientBW2 = 0xff
c.clientBW2 = 0xff
}
case packetTypeInvoke:
err := handleInvoke(s, pkt.body[:pkt.bodySize])
err := handleInvoke(c, pkt.body[:pkt.bodySize])
if err != nil {
s.log(WarnLevel, pkg+"unexpected error from handleInvoke", "error", err.Error())
c.log(WarnLevel, pkg+"unexpected error from handleInvoke", "error", err.Error())
return err
}
case packetTypeControl, packetTypeAudio, packetTypeVideo, packetTypeFlashVideo, packetTypeFlexMessage, packetTypeInfo:
s.log(FatalLevel, pkg+"unsupported packet type "+strconv.Itoa(int(pkt.packetType)))
c.log(FatalLevel, pkg+"unsupported packet type "+strconv.Itoa(int(pkt.packetType)))
default:
s.log(WarnLevel, pkg+"unknown packet type", "type", pkt.packetType)
c.log(WarnLevel, pkg+"unknown packet type", "type", pkt.packetType)
}
return nil
}
func sendConnectPacket(s *Session) error {
func sendConnectPacket(c *Conn) error {
var pbuf [4096]byte
pkt := packet{
channel: chanControl,
@ -300,15 +270,15 @@ func sendConnectPacket(s *Session) error {
if err != nil {
return err
}
s.numInvokes += 1
enc, err = amf.EncodeNumber(enc, float64(s.numInvokes))
c.numInvokes += 1
enc, err = amf.EncodeNumber(enc, float64(c.numInvokes))
if err != nil {
return err
}
enc[0] = amf.TypeObject
enc = enc[1:]
enc, err = amf.EncodeNamedString(enc, avApp, s.link.app)
enc, err = amf.EncodeNamedString(enc, avApp, c.link.app)
if err != nil {
return err
}
@ -316,7 +286,7 @@ func sendConnectPacket(s *Session) error {
if err != nil {
return err
}
enc, err = amf.EncodeNamedString(enc, avTcUrl, s.link.url)
enc, err = amf.EncodeNamedString(enc, avTcUrl, c.link.url)
if err != nil {
return err
}
@ -326,12 +296,12 @@ func sendConnectPacket(s *Session) error {
}
// add auth string, if any
if s.link.auth != "" {
enc, err = amf.EncodeBoolean(enc, s.link.flags&linkAuth != 0)
if c.link.auth != "" {
enc, err = amf.EncodeBoolean(enc, c.link.flags&linkAuth != 0)
if err != nil {
return err
}
enc, err = amf.EncodeString(enc, s.link.auth)
enc, err = amf.EncodeString(enc, c.link.auth)
if err != nil {
return err
}
@ -339,10 +309,10 @@ func sendConnectPacket(s *Session) error {
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
return pkt.writeTo(s, true) // response expected
return pkt.writeTo(c, true) // response expected
}
func sendCreateStream(s *Session) error {
func sendCreateStream(c *Conn) error {
var pbuf [256]byte
pkt := packet{
channel: chanControl,
@ -357,8 +327,8 @@ func sendCreateStream(s *Session) error {
if err != nil {
return err
}
s.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(s.numInvokes))
c.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(c.numInvokes))
if err != nil {
return err
}
@ -367,10 +337,10 @@ func sendCreateStream(s *Session) error {
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
return pkt.writeTo(s, true) // response expected
return pkt.writeTo(c, true) // response expected
}
func sendReleaseStream(s *Session) error {
func sendReleaseStream(c *Conn) error {
var pbuf [1024]byte
pkt := packet{
channel: chanControl,
@ -385,23 +355,23 @@ func sendReleaseStream(s *Session) error {
if err != nil {
return err
}
s.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(s.numInvokes))
c.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(c.numInvokes))
if err != nil {
return err
}
enc[0] = amf.TypeNull
enc = enc[1:]
enc, err = amf.EncodeString(enc, s.link.playpath)
enc, err = amf.EncodeString(enc, c.link.playpath)
if err != nil {
return err
}
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
return pkt.writeTo(s, false)
return pkt.writeTo(c, false)
}
func sendFCPublish(s *Session) error {
func sendFCPublish(c *Conn) error {
var pbuf [1024]byte
pkt := packet{
channel: chanControl,
@ -416,24 +386,24 @@ func sendFCPublish(s *Session) error {
if err != nil {
return err
}
s.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(s.numInvokes))
c.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(c.numInvokes))
if err != nil {
return err
}
enc[0] = amf.TypeNull
enc = enc[1:]
enc, err = amf.EncodeString(enc, s.link.playpath)
enc, err = amf.EncodeString(enc, c.link.playpath)
if err != nil {
return err
}
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
return pkt.writeTo(s, false)
return pkt.writeTo(c, false)
}
func sendFCUnpublish(s *Session) error {
func sendFCUnpublish(c *Conn) error {
var pbuf [1024]byte
pkt := packet{
channel: chanControl,
@ -448,24 +418,24 @@ func sendFCUnpublish(s *Session) error {
if err != nil {
return err
}
s.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(s.numInvokes))
c.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(c.numInvokes))
if err != nil {
return err
}
enc[0] = amf.TypeNull
enc = enc[1:]
enc, err = amf.EncodeString(enc, s.link.playpath)
enc, err = amf.EncodeString(enc, c.link.playpath)
if err != nil {
return err
}
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
return pkt.writeTo(s, false)
return pkt.writeTo(c, false)
}
func sendPublish(s *Session) error {
func sendPublish(c *Conn) error {
var pbuf [1024]byte
pkt := packet{
channel: chanSource,
@ -480,14 +450,14 @@ func sendPublish(s *Session) error {
if err != nil {
return err
}
s.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(s.numInvokes))
c.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(c.numInvokes))
if err != nil {
return err
}
enc[0] = amf.TypeNull
enc = enc[1:]
enc, err = amf.EncodeString(enc, s.link.playpath)
enc, err = amf.EncodeString(enc, c.link.playpath)
if err != nil {
return err
}
@ -498,10 +468,10 @@ func sendPublish(s *Session) error {
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
return pkt.writeTo(s, true) // response expected
return pkt.writeTo(c, true) // response expected
}
func sendDeleteStream(s *Session, dStreamId float64) error {
func sendDeleteStream(c *Conn, dStreamId float64) error {
var pbuf [256]byte
pkt := packet{
channel: chanControl,
@ -516,8 +486,8 @@ func sendDeleteStream(s *Session, dStreamId float64) error {
if err != nil {
return err
}
s.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(s.numInvokes))
c.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(c.numInvokes))
if err != nil {
return err
}
@ -529,11 +499,11 @@ func sendDeleteStream(s *Session, dStreamId float64) error {
}
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
return pkt.writeTo(s, false)
return pkt.writeTo(c, false)
}
// sendBytesReceived tells the server how many bytes the client has received.
func sendBytesReceived(s *Session) error {
func sendBytesReceived(c *Conn) error {
var pbuf [256]byte
pkt := packet{
channel: chanBytesRead,
@ -544,18 +514,18 @@ func sendBytesReceived(s *Session) error {
}
enc := pkt.body
s.nBytesInSent = s.nBytesIn
c.nBytesInSent = c.nBytesIn
enc, err := amf.EncodeInt32(enc, s.nBytesIn)
enc, err := amf.EncodeInt32(enc, c.nBytesIn)
if err != nil {
return err
}
pkt.bodySize = 4
return pkt.writeTo(s, false)
return pkt.writeTo(c, false)
}
func sendCheckBW(s *Session) error {
func sendCheckBW(c *Conn) error {
var pbuf [256]byte
pkt := packet{
channel: chanControl,
@ -570,8 +540,8 @@ func sendCheckBW(s *Session) error {
if err != nil {
return err
}
s.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(s.numInvokes))
c.numInvokes++
enc, err = amf.EncodeNumber(enc, float64(c.numInvokes))
if err != nil {
return err
}
@ -580,7 +550,7 @@ func sendCheckBW(s *Session) error {
pkt.bodySize = uint32((len(pbuf) - fullHeaderSize) - len(enc))
return pkt.writeTo(s, false)
return pkt.writeTo(c, false)
}
func eraseMethod(m []method, i int) []method {
@ -590,8 +560,8 @@ func eraseMethod(m []method, i int) []method {
}
// int handleInvoke handles a packet invoke request
// Side effects: s.isPlaying set to true upon avNetStreamPublish_Start
func handleInvoke(s *Session, body []byte) error {
// Side effects: c.isPlaying set to true upon avNetStreamPublish_Start
func handleInvoke(c *Conn, body []byte) error {
if body[0] != 0x02 {
return errInvalidBody
}
@ -610,37 +580,37 @@ func handleInvoke(s *Session, body []byte) error {
return err
}
s.log(DebugLevel, pkg+"invoking method "+meth)
c.log(DebugLevel, pkg+"invoking method "+meth)
switch meth {
case av_result:
if (s.link.protocol & featureWrite) == 0 {
if (c.link.protocol & featureWrite) == 0 {
return errNotWritable
}
var methodInvoked string
for i, m := range s.methodCalls {
for i, m := range c.methodCalls {
if float64(m.num) == txn {
methodInvoked = m.name
s.methodCalls = eraseMethod(s.methodCalls, i)
c.methodCalls = eraseMethod(c.methodCalls, i)
break
}
}
if methodInvoked == "" {
s.log(WarnLevel, pkg+"received result without matching request", "id", txn)
c.log(WarnLevel, pkg+"received result without matching request", "id", txn)
return nil
}
s.log(DebugLevel, pkg+"received result for "+methodInvoked)
c.log(DebugLevel, pkg+"received result for "+methodInvoked)
switch methodInvoked {
case avConnect:
err := sendReleaseStream(s)
err := sendReleaseStream(c)
if err != nil {
return err
}
err = sendFCPublish(s)
err = sendFCPublish(c)
if err != nil {
return err
}
err = sendCreateStream(s)
err = sendCreateStream(c)
if err != nil {
return err
}
@ -650,18 +620,18 @@ func handleInvoke(s *Session, body []byte) error {
if err != nil {
return err
}
s.streamID = int32(n)
err = sendPublish(s)
c.streamID = int32(n)
err = sendPublish(c)
if err != nil {
return err
}
default:
s.log(FatalLevel, pkg+"unexpected method invoked"+methodInvoked)
c.log(FatalLevel, pkg+"unexpected method invoked"+methodInvoked)
}
case avOnBWDone:
err := sendCheckBW(s)
err := sendCheckBW(c)
if err != nil {
return err
}
@ -679,27 +649,27 @@ func handleInvoke(s *Session, body []byte) error {
if err != nil {
return err
}
s.log(DebugLevel, pkg+"onStatus", "code", code, "level", level)
c.log(DebugLevel, pkg+"onStatus", "code", code, "level", level)
if code != avNetStreamPublish_Start {
s.log(ErrorLevel, pkg+"unexpected response "+code)
c.log(ErrorLevel, pkg+"unexpected response "+code)
return errUnimplemented
}
s.log(DebugLevel, pkg+"playing")
s.isPlaying = true
for i, m := range s.methodCalls {
c.log(DebugLevel, pkg+"playing")
c.isPlaying = true
for i, m := range c.methodCalls {
if m.name == avPublish {
s.methodCalls = eraseMethod(s.methodCalls, i)
c.methodCalls = eraseMethod(c.methodCalls, i)
}
}
default:
s.log(FatalLevel, pkg+"unsuppoted method "+meth)
c.log(FatalLevel, pkg+"unsuppoted method "+meth)
}
return nil
}
func handshake(s *Session) error {
func handshake(c *Conn) error {
var clientbuf [signatureSize + 1]byte
clientsig := clientbuf[1:]
@ -712,44 +682,44 @@ func handshake(s *Session) error {
clientsig[i] = byte(rand.Intn(256))
}
_, err := s.write(clientbuf[:])
_, err := c.write(clientbuf[:])
if err != nil {
return err
}
s.log(DebugLevel, pkg+"handshake sent")
c.log(DebugLevel, pkg+"handshake sent")
var typ [1]byte
_, err = s.read(typ[:])
_, err = c.read(typ[:])
if err != nil {
return err
}
s.log(DebugLevel, pkg+"handshake received")
c.log(DebugLevel, pkg+"handshake received")
if typ[0] != clientbuf[0] {
s.log(WarnLevel, pkg+"handshake type mismatch", "sent", clientbuf[0], "received", typ)
c.log(WarnLevel, pkg+"handshake type mismatch", "sent", clientbuf[0], "received", typ)
}
_, err = s.read(serversig[:])
_, err = c.read(serversig[:])
if err != nil {
return err
}
// decode server response
suptime := binary.BigEndian.Uint32(serversig[:4])
s.log(DebugLevel, pkg+"server uptime", "uptime", suptime)
c.log(DebugLevel, pkg+"server uptime", "uptime", suptime)
// 2nd part of handshake
_, err = s.write(serversig[:])
_, err = c.write(serversig[:])
if err != nil {
return err
}
_, err = s.read(serversig[:])
_, err = c.read(serversig[:])
if err != nil {
return err
}
if !bytes.Equal(serversig[:signatureSize], clientbuf[1:signatureSize+1]) {
s.log(WarnLevel, pkg+"signature mismatch", "serversig", serversig[:signatureSize], "clientsig", clientbuf[1:signatureSize+1])
c.log(WarnLevel, pkg+"signature mismatch", "serversig", serversig[:signatureSize], "clientsig", clientbuf[1:signatureSize+1])
}
return nil
}