Example #1
0
func (req *RtmpRequest) Parse(cc, args *Amf0Object, logger core.Logger) (err error) {
	if v, ok := cc.GetString("tcUrl"); ok {
		req.TcUrl = string(v)
	} else {
		logger.Error("invalid request, must specifies the tcUrl.")
		return RtmpTcUrlNotString
	}

	if v, ok := cc.GetString("pageUrl"); ok {
		req.PageUrl = string(v)
	}
	if v, ok := cc.GetString("swfUrl"); ok {
		req.SwfUrl = string(v)
	}
	if v, ok := cc.GetNumber("objectEncoding"); ok {
		req.ObjectEncoding = int(float64(v))
	}

	if args != nil {
		req.Args = args
		logger.Info("copy edge traverse to origin auth args.")
	}
	logger.Info("get connect app message params success.")

	req.Schema, req.Host, req.Vhost, req.App, req.Port, req.Param, err = DiscoveryTcUrl(req.TcUrl, logger)
	logger.Info("tcUrl=%v parsed", req.TcUrl)

	return
}
Example #2
0
func FindSource(req *protocol.RtmpRequest, logger core.Logger) (source *RtmpSource, err error) {
	url := req.StreamUrl()

	if _, ok := sources[url]; !ok {
		source = NewRtmpSource(req, logger)
		if err = source.Initialize(); err != nil {
			return
		}
		sources[url] = source
		logger.Info("create new source for url=%s, vhost=%s", url, req.Vhost)
	}

	// we always update the request of resource,
	// for origin auth is on, the token in request maybe invalid,
	// and we only need to update the token of request, it's simple.
	source = sources[url]
	source.Req.UpdateAuth(req)

	return
}
Example #3
0
func (req *RtmpRequest) Validate(logger core.Logger) (err error) {
	if req.Schema == "" {
		logger.Error("request schema is empty")
		return RtmpRequestSchemaEmpty
	}
	if req.Vhost == "" {
		logger.Error("request vhost is empty")
		return RtmpRequestVhostEmpty
	}
	if req.Port <= 0 {
		logger.Error("request port is not positive")
		return RtmpRequestPortEmpty
	}
	if req.App == "" {
		logger.Error("request app is empty")
		return RtmpRequestAppEmpty
	}

	logger.Info("request validate ok")

	return
}
Example #4
0
func (pkt *RtmpConnectAppPacket) Decode(buffer *bytes.Buffer, logger core.Logger) (err error) {
	if err = pkt.rtmpCommonCallPacket.Decode(buffer, logger); err != nil {
		return
	}

	// some client donot send id=1.0, so we only warn user if not match.
	if pkt.TransactionId != 1.0 {
		logger.Warn("connect should be 1.0, actual is %v", pkt.TransactionId)
	}

	if err = pkt.CommandObject.Decode(buffer); err != nil {
		logger.Error("amf0 decode connect command_object failed.")
		return
	}

	if buffer.Len() > 0 {
		// see: https://github.com/winlinvip/simple-rtmp-server/issues/186
		// the args maybe any amf0, for instance, a string. we should drop if not object.
		var any Amf0Any
		if any, err = DecodeAmf0Any(buffer); err != nil {
			logger.Error("amf0 decode connect args failed")
			return
		}

		// drop when not an AMF0 object.
		if any.(*Amf0Object) == nil {
			logger.Warn("drop the args, see: '4.1.1. connect'")
		} else {
			pkt.Arguments = any.(*Amf0Object)
		}
	}

	logger.Info("amf0 decode connect packet success")

	return
}
Example #5
0
func DiscoveryTcUrl(tcUrl string, logger core.Logger) (schema, host, vhost, app string, port int, param string, err error) {
	rawurl := tcUrl

	// parse the ...vhost... to standard query &vhost=
	for strings.Index(rawurl, "...") >= 0 {
		rawurl = strings.Replace(rawurl, "...", "&", 1)
		rawurl = strings.Replace(rawurl, "...", "=", 1)
	}

	// use url module to parse.
	var uri *url.URL
	if uri, err = url.Parse(tcUrl); err != nil {
		logger.Error("parse tcUrl=%v failed", tcUrl)
		return
	}

	schema = uri.Scheme
	host = uri.Host
	app = strings.Trim(uri.Path, "/")
	param = uri.RawQuery

	port = core.SRS_CONSTS_RTMP_DEFAULT_PORT
	if pos := strings.Index(host, ":"); pos >= 0 {
		if port, err = strconv.Atoi(host[pos+1:]); err != nil {
			logger.Error("parse port from host=%v failed", host)
			return
		}
		host = host[0:pos]
		logger.Info("discovery host=%v, port=%v", host, port)
	}

	vhost = host
	query := uri.Query()
	if query.Get("vhost") != "" {
		vhost = query.Get("vhost")
	}

	logger.Info("tcUrl parsed to schema=%v, host=%v, port=%v, vhost=%v, app=%v, param=%v",
		schema, host, port, vhost, app, param)

	return
}
Example #6
0
func DiscoveryPacket(msg *RtmpMessage, logger core.Logger) (b []byte, pkt RtmpPacket, err error) {
	header := msg.Header
	b = msg.Payload

	if msg == nil || len(msg.Payload) == 0 {
		logger.Info("ignore empty msg")
		return
	}

	// decode specified packet type
	if header.IsAmf0Command() || header.IsAmf3Command() || header.IsAmf0Data() || header.IsAmf3Data() {
		logger.Info("start to decode AMF0/AMF3 command message.")

		// skip 1bytes to decode the amf3 command.
		if header.IsAmf3Command() {
			b = b[1:]
			logger.Info("skip 1bytes to decode AMF3 command")
		}

		// amf0 command message.
		// need to read the command name.
		var command Amf0String
		if command, err = DecodeAmf0String(bytes.NewBuffer(b)); err != nil {
			logger.Error("decode AMF0/AMF3 command name failed.")
			return
		}
		logger.Info("AMF0/AMF3 command message, command_name=%v", command)

		// result/error packet
		if command == RTMP_AMF0_COMMAND_RESULT || command == RTMP_AMF0_COMMAND_ERROR {
		}

		// decode command object.
		switch command {
		case RTMP_AMF0_COMMAND_CONNECT:
			logger.Info("decode the AMF0/AMF3 command(connect vhost/app message).")
			pkt = NewRtmpConnectAppPacket()
		case RTMP_AMF0_COMMAND_CREATE_STREAM:
			logger.Info("decode the AMF0/AMF3 command(createStream message).")
			pkt = NewRtmpCreateStreamPacket()
		case RTMP_AMF0_COMMAND_PLAY:
			logger.Info("decode the AMF0/AMF3 command(paly message).")
			pkt = NewRtmpPlayPacket()
		case RTMP_AMF0_COMMAND_RELEASE_STREAM:
			logger.Info("decode the AMF0/AMF3 command(FMLE releaseStream message).")
			pkt = NewRtmpReleaseStreamPacket()
		case RTMP_AMF0_COMMAND_FC_PUBLISH:
			logger.Info("decode the AMF0/AMF3 command(FMLE FCPublish message).")
			pkt = NewRtmpFcPublishPacket()
		case RTMP_AMF0_COMMAND_UNPUBLISH:
			logger.Info("decode the AMF0/AMF3 command(FMLE FCUnpublish message).")
			pkt = NewRtmpFcUnPublishPacket()
		case RTMP_AMF0_COMMAND_PUBLISH:
			logger.Info("decode the AMF0/AMF3 command(publish message).")
			pkt = NewRtmpPublishPacket()
		default:
			if header.IsAmf0Command() || header.IsAmf3Command() {
				logger.Info("decode the AMF0/AMF3 call message.")
				pkt = NewRtmpCallPacket()
			} else {
				logger.Info("drop the AMF0/AMF3 command message, command_name=%v", command)
			}
		}
	} else if header.IsUserControlMessage() {
		logger.Info("start to decode user control message.")
		pkt = NewRtmpUserControlPacket()
	} else if header.IsWindowAckledgementSize() {
		logger.Info("start to decode set ack window size message.")
		pkt = NewRtmpSetWindowAckSizePacket(0)
	} else if header.IsSetChunkSize() {
		logger.Info("start to decode set chunk size message.")
		pkt = NewRtmpSetChunkSizePacket()
	} else {
	}

	return
}