diff options
-rw-r--r-- | core/io/net_socket.h | 2 | ||||
-rw-r--r-- | core/io/packet_peer_udp.cpp | 11 | ||||
-rw-r--r-- | core/io/packet_peer_udp.h | 2 | ||||
-rw-r--r-- | doc/classes/PacketPeerUDP.xml | 12 | ||||
-rw-r--r-- | drivers/unix/net_socket_posix.cpp | 16 | ||||
-rw-r--r-- | drivers/unix/net_socket_posix.h | 2 | ||||
-rw-r--r-- | platform/android/SCsub | 1 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/Godot.java | 3 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java | 84 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java | 18 | ||||
-rw-r--r-- | platform/android/java_godot_lib_jni.cpp | 2 | ||||
-rw-r--r-- | platform/android/net_socket_android.cpp | 136 | ||||
-rw-r--r-- | platform/android/net_socket_android.h | 78 | ||||
-rw-r--r-- | platform/android/os_android.cpp | 3 |
14 files changed, 362 insertions, 8 deletions
diff --git a/core/io/net_socket.h b/core/io/net_socket.h index 3bc1369487..914e243b65 100644 --- a/core/io/net_socket.h +++ b/core/io/net_socket.h @@ -69,7 +69,7 @@ public: virtual bool is_open() const = 0; virtual int get_available_bytes() const = 0; - virtual void set_broadcasting_enabled(bool p_enabled) = 0; + virtual Error set_broadcasting_enabled(bool p_enabled) = 0; // Returns OK if the socket option has been set successfully. virtual void set_blocking_enabled(bool p_enabled) = 0; virtual void set_ipv6_only_enabled(bool p_enabled) = 0; virtual void set_tcp_no_delay_enabled(bool p_enabled) = 0; diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index 7e9471c053..80a070cf1c 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -37,6 +37,12 @@ void PacketPeerUDP::set_blocking_mode(bool p_enable) { blocking = p_enable; } +void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) { + broadcast = p_enabled; + if (_sock.is_valid() && _sock->is_open()) + _sock->set_broadcasting_enabled(p_enabled); +} + Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_if_name) { ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); @@ -47,6 +53,7 @@ Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_i Error err = _sock->open(NetSocket::TYPE_UDP, ip_type); ERR_FAIL_COND_V(err != OK, err); _sock->set_blocking_enabled(false); + _sock->set_broadcasting_enabled(broadcast); } return _sock->join_multicast_group(p_multi_address, p_if_name); } @@ -122,6 +129,7 @@ Error PacketPeerUDP::put_packet(const uint8_t *p_buffer, int p_buffer_size) { err = _sock->open(NetSocket::TYPE_UDP, ip_type); ERR_FAIL_COND_V(err != OK, err); _sock->set_blocking_enabled(false); + _sock->set_broadcasting_enabled(broadcast); } do { @@ -165,6 +173,7 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_ _sock->set_blocking_enabled(false); _sock->set_reuse_address_enabled(true); + _sock->set_broadcasting_enabled(broadcast); err = _sock->bind(p_bind_address, p_port); if (err != OK) { @@ -258,6 +267,7 @@ void PacketPeerUDP::_bind_methods() { ClassDB::bind_method(D_METHOD("get_packet_ip"), &PacketPeerUDP::_get_packet_ip); ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port); ClassDB::bind_method(D_METHOD("set_dest_address", "host", "port"), &PacketPeerUDP::_set_dest_address); + ClassDB::bind_method(D_METHOD("set_broadcast_enabled", "enabled"), &PacketPeerUDP::set_broadcast_enabled); ClassDB::bind_method(D_METHOD("join_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::join_multicast_group); ClassDB::bind_method(D_METHOD("leave_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::leave_multicast_group); } @@ -267,6 +277,7 @@ PacketPeerUDP::PacketPeerUDP() : queue_count(0), peer_port(0), blocking(true), + broadcast(false), _sock(Ref<NetSocket>(NetSocket::create())) { rb.resize(16); } diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h index 068bd5cd5a..dc89e129dd 100644 --- a/core/io/packet_peer_udp.h +++ b/core/io/packet_peer_udp.h @@ -53,6 +53,7 @@ protected: IP_Address peer_addr; int peer_port; bool blocking; + bool broadcast; Ref<NetSocket> _sock; static void _bind_methods(); @@ -77,6 +78,7 @@ public: Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); int get_available_packet_count() const; int get_max_packet_size() const; + void set_broadcast_enabled(bool p_enabled); Error join_multicast_group(IP_Address p_multi_address, String p_if_name); Error leave_multicast_group(IP_Address p_multi_address, String p_if_name); diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml index 260dbae8e2..3dc83ce8b4 100644 --- a/doc/classes/PacketPeerUDP.xml +++ b/doc/classes/PacketPeerUDP.xml @@ -47,6 +47,7 @@ <description> Joins the multicast group specified by [code]multicast_address[/code] using the interface identified by [code]interface_name[/code]. You can join the same multicast group with multiple interfaces. Use [method IP.get_local_interfaces] to know which are available. + Note: Some Android devices might require the [code]CHANGE_WIFI_MULTICAST_STATE[/code] permission for multicast to work. </description> </method> <method name="leave_multicast_group"> @@ -76,6 +77,16 @@ If [code]bind_address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only listen on the interface with that addresses (or fail if no interface with the given address exists). </description> </method> + <method name="set_broadcast_enabled"> + <return type="void"> + </return> + <argument index="0" name="enabled" type="bool"> + </argument> + <description> + Enable or disable sending of broadcast packets (e.g. [code]set_dest_address("255.255.255.255", 4343)[/code]. This option is disabled by default. + Note: Some Android devices might require the [code]CHANGE_WIFI_MULTICAST_STATE[/code] permission and this option to be enabled to receive broadcast packets too. + </description> + </method> <method name="set_dest_address"> <return type="int" enum="Error"> </return> @@ -85,6 +96,7 @@ </argument> <description> Sets the destination address and port for sending packets and variables. A hostname will be resolved using DNS if needed. + Note: [method set_broadcast_enabled] must be enabled before sending packets to a broadcast address (e.g. [code]255.255.255.255[/code]). </description> </method> <method name="wait"> diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 5f99a40c79..003c372107 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -333,9 +333,10 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { set_ipv6_only_enabled(ip_type != IP::TYPE_ANY); } - if (protocol == IPPROTO_UDP && ip_type != IP::TYPE_IPV6) { - // Enable broadcasting for UDP sockets if it's not IPv6 only (IPv6 has no broadcast option). - set_broadcasting_enabled(true); + if (protocol == IPPROTO_UDP) { + // Make sure to disable broadcasting for UDP sockets. + // Depending on the OS, this option might or might not be enabled by default. Let's normalize it. + set_broadcasting_enabled(false); } _is_stream = p_sock_type == TYPE_TCP; @@ -603,15 +604,18 @@ Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP return OK; } -void NetSocketPosix::set_broadcasting_enabled(bool p_enabled) { - ERR_FAIL_COND(!is_open()); +Error NetSocketPosix::set_broadcasting_enabled(bool p_enabled) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); // IPv6 has no broadcast support. - ERR_FAIL_COND(_ip_type == IP::TYPE_IPV6); + if (_ip_type == IP::TYPE_IPV6) + return ERR_UNAVAILABLE; int par = p_enabled ? 1 : 0; if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, SOCK_CBUF(&par), sizeof(int)) != 0) { WARN_PRINT("Unable to change broadcast setting"); + return FAILED; } + return OK; } void NetSocketPosix::set_blocking_enabled(bool p_enabled) { diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index e549ea1d6a..fe5a4858de 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -89,7 +89,7 @@ public: virtual bool is_open() const; virtual int get_available_bytes() const; - virtual void set_broadcasting_enabled(bool p_enabled); + virtual Error set_broadcasting_enabled(bool p_enabled); virtual void set_blocking_enabled(bool p_enabled); virtual void set_ipv6_only_enabled(bool p_enabled); virtual void set_tcp_no_delay_enabled(bool p_enabled); diff --git a/platform/android/SCsub b/platform/android/SCsub index 65172a12c0..3ff5b8278a 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -12,6 +12,7 @@ android_files = [ 'file_access_jandroid.cpp', 'dir_access_jandroid.cpp', 'thread_jandroid.cpp', + 'net_socket_android.cpp', 'audio_driver_jandroid.cpp', 'java_godot_lib_jni.cpp', 'java_class_wrapper.cpp', diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 4dae2dcc53..d951998632 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -96,6 +96,7 @@ import java.util.Locale; import javax.microedition.khronos.opengles.GL10; import org.godotengine.godot.input.GodotEditText; import org.godotengine.godot.payments.PaymentsManager; +import org.godotengine.godot.utils.GodotNetUtils; import org.godotengine.godot.utils.PermissionsUtil; import org.godotengine.godot.xr.XRMode; @@ -243,6 +244,7 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo private Sensor mGyroscope; public static GodotIO io; + public static GodotNetUtils netUtils; static SingletonBase[] singletons = new SingletonBase[MAX_SINGLETONS]; static int singleton_count = 0; @@ -502,6 +504,7 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo io = new GodotIO(this); io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID); GodotLib.io = io; + netUtils = new GodotNetUtils(this); mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java b/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java new file mode 100644 index 0000000000..0dc6962ca6 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java @@ -0,0 +1,84 @@ +/*************************************************************************/ +/* GodotNetUtils.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.utils; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.util.Log; + +import org.godotengine.godot.Godot; + +/** + * This class handles Android-specific networking functions. + * For now, it only provides access to WifiManager.MulticastLock, which is needed on some devices + * to receive broadcast and multicast packets. + */ +public class GodotNetUtils { + + /* A single, reference counted, multicast lock, or null if permission CHANGE_WIFI_MULTICAST_STATE is missing */ + private WifiManager.MulticastLock multicastLock; + + public GodotNetUtils(Godot p_activity) { + if (PermissionsUtil.hasManifestPermission(p_activity, "android.permission.CHANGE_WIFI_MULTICAST_STATE")) { + WifiManager wifi = (WifiManager)p_activity.getApplicationContext().getSystemService(Context.WIFI_SERVICE); + multicastLock = wifi.createMulticastLock("GodotMulticastLock"); + multicastLock.setReferenceCounted(true); + } + } + + /** + * Acquire the multicast lock. This is required on some devices to receive broadcast/multicast packets. + * This is done automatically by Godot when enabling broadcast or joining a multicast group on a socket. + */ + public void multicastLockAcquire() { + if (multicastLock == null) + return; + try { + multicastLock.acquire(); + } catch (RuntimeException e) { + Log.e("Godot", "Exception during multicast lock acquire: " + e); + } + } + + /** + * Release the multicast lock. + * This is done automatically by Godot when the lock is no longer needed by a socket. + */ + public void multicastLockRelease() { + if (multicastLock == null) + return; + try { + multicastLock.release(); + } catch (RuntimeException e) { + Log.e("Godot", "Exception during multicast lock release: " + e); + } + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java index 21df5a91b0..7e35417c6a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java @@ -162,6 +162,24 @@ public final class PermissionsUtil { } /** + * Check if the given permission is in the AndroidManifest.xml file. + * @param activity the caller activity for this method. + * @param permission the permession to look for in the manifest file. + * @return "true" if the permission is in the manifest file of the activity, "false" otherwise. + */ + public static boolean hasManifestPermission(Godot activity, String permission) { + try { + for (String p : getManifestPermissions(activity)) { + if (permission.equals(p)) + return true; + } + } catch (PackageManager.NameNotFoundException e) { + } + + return false; + } + + /** * Returns the permissions defined in the AndroidManifest.xml file. * @param activity the caller activity for this method. * @return manifest permissions list diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index a14e0a1960..1ad1fb0afe 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -43,6 +43,7 @@ #include "java_class_wrapper.h" #include "main/input_default.h" #include "main/main.h" +#include "net_socket_android.h" #include "os_android.h" #include "string_android.h" #include "thread_jandroid.h" @@ -635,6 +636,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en DirAccessJAndroid::setup(godot_io_java->get_instance()); AudioDriverAndroid::setup(godot_io_java->get_instance()); + NetSocketAndroid::setup(godot_java->get_member_object("netUtils", "Lorg/godotengine/godot/utils/GodotNetUtils;", env)); os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion); diff --git a/platform/android/net_socket_android.cpp b/platform/android/net_socket_android.cpp new file mode 100644 index 0000000000..78ef354c21 --- /dev/null +++ b/platform/android/net_socket_android.cpp @@ -0,0 +1,136 @@ +/*************************************************************************/ +/* net_socket_android.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "net_socket_android.h" + +#include "thread_jandroid.h" + +jobject NetSocketAndroid::net_utils = 0; +jclass NetSocketAndroid::cls = 0; +jmethodID NetSocketAndroid::_multicast_lock_acquire = 0; +jmethodID NetSocketAndroid::_multicast_lock_release = 0; + +void NetSocketAndroid::setup(jobject p_net_utils) { + + JNIEnv *env = ThreadAndroid::get_env(); + + net_utils = env->NewGlobalRef(p_net_utils); + + jclass c = env->GetObjectClass(net_utils); + cls = (jclass)env->NewGlobalRef(c); + + _multicast_lock_acquire = env->GetMethodID(cls, "multicastLockAcquire", "()V"); + _multicast_lock_release = env->GetMethodID(cls, "multicastLockRelease", "()V"); +} + +void NetSocketAndroid::multicast_lock_acquire() { + if (_multicast_lock_acquire) { + JNIEnv *env = ThreadAndroid::get_env(); + env->CallVoidMethod(net_utils, _multicast_lock_acquire); + } +} + +void NetSocketAndroid::multicast_lock_release() { + if (_multicast_lock_release) { + JNIEnv *env = ThreadAndroid::get_env(); + env->CallVoidMethod(net_utils, _multicast_lock_release); + } +} + +NetSocket *NetSocketAndroid::_create_func() { + return memnew(NetSocketAndroid); +} + +void NetSocketAndroid::make_default() { + _create = _create_func; +} + +NetSocketAndroid::NetSocketAndroid() : + wants_broadcast(false), + multicast_groups(0) { +} + +NetSocketAndroid::~NetSocketAndroid() { + close(); +} + +void NetSocketAndroid::close() { + NetSocketPosix::close(); + if (wants_broadcast) + multicast_lock_release(); + if (multicast_groups) + multicast_lock_release(); + wants_broadcast = false; + multicast_groups = 0; +} + +Error NetSocketAndroid::set_broadcasting_enabled(bool p_enabled) { + Error err = NetSocketPosix::set_broadcasting_enabled(p_enabled); + if (err != OK) + return err; + + if (p_enabled != wants_broadcast) { + if (p_enabled) { + multicast_lock_acquire(); + } else { + multicast_lock_release(); + } + + wants_broadcast = p_enabled; + } + + return OK; +} + +Error NetSocketAndroid::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) { + Error err = NetSocketPosix::join_multicast_group(p_multi_address, p_if_name); + if (err != OK) + return err; + + if (!multicast_groups) + multicast_lock_acquire(); + multicast_groups++; + + return OK; +} + +Error NetSocketAndroid::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) { + Error err = NetSocketPosix::leave_multicast_group(p_multi_address, p_if_name); + if (err != OK) + return err; + + ERR_FAIL_COND_V(multicast_groups == 0, ERR_BUG); + + multicast_groups--; + if (!multicast_groups) + multicast_lock_release(); + + return OK; +} diff --git a/platform/android/net_socket_android.h b/platform/android/net_socket_android.h new file mode 100644 index 0000000000..1ecbac0c1a --- /dev/null +++ b/platform/android/net_socket_android.h @@ -0,0 +1,78 @@ +/*************************************************************************/ +/* net_socket_android.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef NET_SOCKET_ANDROID_H +#define NET_SOCKET_ANDROID_H + +#include "drivers/unix/net_socket_posix.h" + +#include <jni.h> + +/** + * Specialized NetSocket implementation for Android. + * + * Some devices requires Android-specific code to acquire a MulticastLock + * before sockets are allowed to receive broadcast and multicast packets. + * This implementation calls into Java code and automatically acquire/release + * the lock when broadcasting is enabled/disabled on a socket, or that socket + * joins/leaves a multicast group. + */ +class NetSocketAndroid : public NetSocketPosix { + +private: + static jobject net_utils; + static jclass cls; + static jmethodID _multicast_lock_acquire; + static jmethodID _multicast_lock_release; + + bool wants_broadcast; + int multicast_groups; + + static void multicast_lock_acquire(); + static void multicast_lock_release(); + +protected: + static NetSocket *_create_func(); + +public: + static void make_default(); + static void setup(jobject p_net_utils); + + virtual void close(); + + virtual Error set_broadcasting_enabled(bool p_enabled); + virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name); + virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name); + + NetSocketAndroid(); + ~NetSocketAndroid(); +}; + +#endif diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 9068b76cfb..f08dcc449e 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -43,6 +43,7 @@ #include "dir_access_jandroid.h" #include "file_access_jandroid.h" +#include "net_socket_android.h" #include <dlfcn.h> @@ -106,6 +107,8 @@ void OS_Android::initialize_core() { DirAccess::make_default<DirAccessJAndroid>(DirAccess::ACCESS_RESOURCES); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM); + + NetSocketAndroid::make_default(); } void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { |