avm2: Implement many NetConnection properties

This commit is contained in:
Nathan Adams 2023-11-02 19:37:33 +01:00
parent 08c707caa6
commit 6d901a7463
9 changed files with 502 additions and 0 deletions

View File

@ -307,6 +307,20 @@ pub fn make_error_2008<'gc>(activation: &mut Activation<'_, 'gc>, param_name: &s
}
}
#[inline(never)]
#[cold]
pub fn make_error_2126<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> {
let err = argument_error(
activation,
"Error #2126: NetConnection object must be connected.",
2126,
);
match err {
Ok(err) => Error::AvmError(err),
Err(err) => err,
}
}
#[inline(never)]
#[cold]
pub fn make_error_2025<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> {

View File

@ -9,6 +9,9 @@ package flash.net {
public static var defaultObjectEncoding:uint = 3;
public var objectEncoding:uint = NetConnection.defaultObjectEncoding;
public var client:Object = this;
public var maxPeerConnections:uint = 8;
public var proxyType:String = "none";
public native function connect(command:String, ... arguments):void;
@ -22,5 +25,24 @@ package flash.net {
}
public native function close():void;
public native function get connected():Boolean;
public native function get connectedProxyType():String;
public native function get farID():String;
public native function get farNonce():String;
public native function get nearID():String;
public native function get nearNonce():String;
public native function get protocol():String;
public native function get uri():String;
public native function get usingTLS():Boolean;
public function get unconnectedPeerStreams():Array {
if (this.connected) {
// [NA] Arguably this isn't a stub as it can't ever be anything else in our current implementation...
return [];
} else {
throw new ArgumentError("Error #2126: NetConnection object must be connected.", 2126);
}
}
}
}

View File

@ -1,7 +1,9 @@
use crate::avm2::error::make_error_2126;
pub use crate::avm2::object::net_connection_allocator;
use crate::avm2::object::TObject;
use crate::avm2::parameters::ParametersExt;
use crate::net_connection::NetConnections;
use crate::string::AvmString;
use crate::{
avm2::{Activation, Error, Object, Value},
avm2_stub_method,
@ -58,3 +60,177 @@ pub fn close<'gc>(
Ok(Value::Undefined)
}
pub fn get_connected<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(handle) = this.handle() {
return Ok(activation
.context
.net_connections
.is_connected(handle)
.into());
}
Ok(false.into())
}
pub fn get_connected_proxy_type<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(result) = this.handle().and_then(|handle| {
activation
.context
.net_connections
.get_connected_proxy_type(handle)
}) {
return Ok(result.into());
}
Err(make_error_2126(activation))
}
pub fn get_far_id<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(result) = this
.handle()
.and_then(|handle| activation.context.net_connections.get_far_id(handle))
{
return Ok(result.into());
}
Err(make_error_2126(activation))
}
pub fn get_far_nonce<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(result) = this
.handle()
.and_then(|handle| activation.context.net_connections.get_far_nonce(handle))
{
return Ok(result.into());
}
Err(make_error_2126(activation))
}
pub fn get_near_id<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(result) = this
.handle()
.and_then(|handle| activation.context.net_connections.get_near_id(handle))
{
return Ok(result.into());
}
Err(make_error_2126(activation))
}
pub fn get_near_nonce<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(result) = this
.handle()
.and_then(|handle| activation.context.net_connections.get_near_nonce(handle))
{
return Ok(result.into());
}
Err(make_error_2126(activation))
}
pub fn get_protocol<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(result) = this
.handle()
.and_then(|handle| activation.context.net_connections.get_protocol(handle))
{
return Ok(result.into());
}
Err(make_error_2126(activation))
}
pub fn get_uri<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(result) = this
.handle()
.and_then(|handle| activation.context.net_connections.get_uri(handle))
{
return Ok(AvmString::new_utf8(activation.context.gc_context, result).into());
}
Ok(Value::Null)
}
pub fn get_using_tls<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this
.as_net_connection()
.expect("Must be NetConnection object");
if let Some(result) = this
.handle()
.and_then(|handle| activation.context.net_connections.is_using_tls(handle))
{
return Ok(result.into());
}
Err(make_error_2126(activation))
}

View File

@ -133,6 +133,47 @@ impl<'gc> NetConnections<'gc> {
}
}
}
pub fn is_connected(&self, handle: NetConnectionHandle) -> bool {
self.connections
.get(handle)
.map(|c| c.is_connected())
.unwrap_or_default()
}
pub fn get_connected_proxy_type(&self, handle: NetConnectionHandle) -> Option<&'static str> {
self.connections
.get(handle)
.and_then(|c| c.connected_proxy_type())
}
pub fn get_far_id(&self, handle: NetConnectionHandle) -> Option<&'static str> {
self.connections.get(handle).and_then(|c| c.far_id())
}
pub fn get_far_nonce(&self, handle: NetConnectionHandle) -> Option<&'static str> {
self.connections.get(handle).and_then(|c| c.far_nonce())
}
pub fn get_near_id(&self, handle: NetConnectionHandle) -> Option<&'static str> {
self.connections.get(handle).and_then(|c| c.near_id())
}
pub fn get_near_nonce(&self, handle: NetConnectionHandle) -> Option<&'static str> {
self.connections.get(handle).and_then(|c| c.near_nonce())
}
pub fn get_protocol(&self, handle: NetConnectionHandle) -> Option<&'static str> {
self.connections.get(handle).and_then(|c| c.protocol())
}
pub fn get_uri(&self, handle: NetConnectionHandle) -> Option<String> {
self.connections.get(handle).and_then(|c| c.uri())
}
pub fn is_using_tls(&self, handle: NetConnectionHandle) -> Option<bool> {
self.connections.get(handle).and_then(|c| c.using_tls())
}
}
#[derive(Collect)]
@ -144,6 +185,75 @@ pub struct NetConnection<'gc> {
protocol: NetConnectionProtocol,
}
impl<'gc> NetConnection<'gc> {
pub fn is_connected(&self) -> bool {
match self.protocol {
NetConnectionProtocol::Local => true,
NetConnectionProtocol::FlashRemoting(_) => false,
}
}
pub fn connected_proxy_type(&self) -> Option<&'static str> {
match self.protocol {
NetConnectionProtocol::Local => Some("none"),
NetConnectionProtocol::FlashRemoting(_) => None,
}
}
pub fn far_id(&self) -> Option<&'static str> {
match self.protocol {
NetConnectionProtocol::Local => Some(""),
NetConnectionProtocol::FlashRemoting(_) => None,
}
}
pub fn far_nonce(&self) -> Option<&'static str> {
match self.protocol {
NetConnectionProtocol::Local => {
Some("0000000000000000000000000000000000000000000000000000000000000000")
}
NetConnectionProtocol::FlashRemoting(_) => None,
}
}
pub fn near_id(&self) -> Option<&'static str> {
match self.protocol {
NetConnectionProtocol::Local => Some(""),
NetConnectionProtocol::FlashRemoting(_) => None,
}
}
pub fn near_nonce(&self) -> Option<&'static str> {
match self.protocol {
NetConnectionProtocol::Local => {
Some("0000000000000000000000000000000000000000000000000000000000000000")
}
NetConnectionProtocol::FlashRemoting(_) => None,
}
}
pub fn protocol(&self) -> Option<&'static str> {
match self.protocol {
NetConnectionProtocol::Local => Some("rtmp"),
NetConnectionProtocol::FlashRemoting(_) => None,
}
}
pub fn uri(&self) -> Option<String> {
match &self.protocol {
NetConnectionProtocol::Local => Some("null".to_string()), // Yes, it's a string "null", not a real null.
NetConnectionProtocol::FlashRemoting(remoting) => Some(remoting.url.to_string()),
}
}
pub fn using_tls(&self) -> Option<bool> {
match &self.protocol {
NetConnectionProtocol::Local => Some(false),
NetConnectionProtocol::FlashRemoting(_) => None,
}
}
}
#[derive(Debug)]
pub enum NetConnectionProtocol {
/// A "local" connection, caused by connecting to null

View File

@ -0,0 +1,100 @@
package {
import flash.display.MovieClip;
import flash.net.NetConnection;
import flash.net.NetConnection;
import flash.events.NetStatusEvent;
public class Test extends MovieClip {
public function Test() {
var connection:NetConnection = new NetConnection();
traceProperties(connection);
trace("");
trace("/// connection.connect(null)");
connection.connect(null);
traceProperties(connection);
trace("");
trace("/// connection.connect(\"http://example.org\")");
connection.connect("http://example.org");
traceProperties(connection);
trace("");
trace("/// connection.close()");
connection.close();
traceProperties(connection);
trace("");
trace("/// connection.connect(\"https://example.org\")");
connection.connect("https://example.org");
traceProperties(connection);
trace("");
}
function traceSafe(connection: NetConnection, key: String) {
try {
var value = connection[key];
if (typeof(value) === "string") {
trace("connection." + key + " = \"" + escapeString(value) + "\"");
} else if (value is Array) {
trace("connection." + key + " = [" + value + "]");
} else if (value === connection) {
trace("connection." + key + " = connection");
} else {
trace("connection." + key + " = " + value);
}
} catch (error) {
trace("connection." + key + " = " + error);
}
}
function traceProperties(connection: NetConnection) {
traceSafe(connection, "client");
traceSafe(connection, "connected");
traceSafe(connection, "connectedProxyType");
traceSafe(connection, "farID");
traceSafe(connection, "farNonce");
traceSafe(connection, "maxPeerConnections");
traceSafe(connection, "nearID");
traceSafe(connection, "nearNonce");
traceSafe(connection, "objectEncoding");
traceSafe(connection, "protocol");
traceSafe(connection, "proxyType");
traceSafe(connection, "unconnectedPeerStreams");
traceSafe(connection, "uri");
traceSafe(connection, "usingTLS");
}
function escapeString(input: String): String {
var output:String = "";
for (var i:int = 0; i < input.length; i++) {
var char:String = input.charAt(i);
switch (char) {
case "\\":
output += "\\\\";
break;
case "\"":
output += "\\\"";
break;
case "\n":
output += "\\n";
break;
case "\r":
output += "\\r";
break;
case "\t":
output += "\\t";
break;
default:
output += char;
}
}
return output;
}
}
}

View File

@ -0,0 +1,79 @@
connection.client = connection
connection.connected = false
connection.connectedProxyType = ArgumentError: Error #2126: NetConnection object must be connected.
connection.farID = ArgumentError: Error #2126: NetConnection object must be connected.
connection.farNonce = ArgumentError: Error #2126: NetConnection object must be connected.
connection.maxPeerConnections = 8
connection.nearID = ArgumentError: Error #2126: NetConnection object must be connected.
connection.nearNonce = ArgumentError: Error #2126: NetConnection object must be connected.
connection.objectEncoding = 3
connection.protocol = ArgumentError: Error #2126: NetConnection object must be connected.
connection.proxyType = "none"
connection.unconnectedPeerStreams = ArgumentError: Error #2126: NetConnection object must be connected.
connection.uri = null
connection.usingTLS = ArgumentError: Error #2126: NetConnection object must be connected.
/// connection.connect(null)
connection.client = connection
connection.connected = true
connection.connectedProxyType = "none"
connection.farID = ""
connection.farNonce = "0000000000000000000000000000000000000000000000000000000000000000"
connection.maxPeerConnections = 8
connection.nearID = ""
connection.nearNonce = "0000000000000000000000000000000000000000000000000000000000000000"
connection.objectEncoding = 3
connection.protocol = "rtmp"
connection.proxyType = "none"
connection.unconnectedPeerStreams = []
connection.uri = "null"
connection.usingTLS = false
/// connection.connect("http://example.org")
connection.client = connection
connection.connected = false
connection.connectedProxyType = ArgumentError: Error #2126: NetConnection object must be connected.
connection.farID = ArgumentError: Error #2126: NetConnection object must be connected.
connection.farNonce = ArgumentError: Error #2126: NetConnection object must be connected.
connection.maxPeerConnections = 8
connection.nearID = ArgumentError: Error #2126: NetConnection object must be connected.
connection.nearNonce = ArgumentError: Error #2126: NetConnection object must be connected.
connection.objectEncoding = 3
connection.protocol = ArgumentError: Error #2126: NetConnection object must be connected.
connection.proxyType = "none"
connection.unconnectedPeerStreams = ArgumentError: Error #2126: NetConnection object must be connected.
connection.uri = "http://example.org"
connection.usingTLS = ArgumentError: Error #2126: NetConnection object must be connected.
/// connection.close()
connection.client = connection
connection.connected = false
connection.connectedProxyType = ArgumentError: Error #2126: NetConnection object must be connected.
connection.farID = ArgumentError: Error #2126: NetConnection object must be connected.
connection.farNonce = ArgumentError: Error #2126: NetConnection object must be connected.
connection.maxPeerConnections = 8
connection.nearID = ArgumentError: Error #2126: NetConnection object must be connected.
connection.nearNonce = ArgumentError: Error #2126: NetConnection object must be connected.
connection.objectEncoding = 3
connection.protocol = ArgumentError: Error #2126: NetConnection object must be connected.
connection.proxyType = "none"
connection.unconnectedPeerStreams = ArgumentError: Error #2126: NetConnection object must be connected.
connection.uri = null
connection.usingTLS = ArgumentError: Error #2126: NetConnection object must be connected.
/// connection.connect("https://example.org")
connection.client = connection
connection.connected = false
connection.connectedProxyType = ArgumentError: Error #2126: NetConnection object must be connected.
connection.farID = ArgumentError: Error #2126: NetConnection object must be connected.
connection.farNonce = ArgumentError: Error #2126: NetConnection object must be connected.
connection.maxPeerConnections = 8
connection.nearID = ArgumentError: Error #2126: NetConnection object must be connected.
connection.nearNonce = ArgumentError: Error #2126: NetConnection object must be connected.
connection.objectEncoding = 3
connection.protocol = ArgumentError: Error #2126: NetConnection object must be connected.
connection.proxyType = "none"
connection.unconnectedPeerStreams = ArgumentError: Error #2126: NetConnection object must be connected.
connection.uri = "https://example.org"
connection.usingTLS = ArgumentError: Error #2126: NetConnection object must be connected.

View File

@ -0,0 +1 @@
num_frames = 1