Ladybird/Android: Bind WebSocketService for WebSocket purposes

Similar to the RequestServer, bind this from the WebContentService
implementation and have it work the same way. Deduplicate some code
while we're here.
This commit is contained in:
Andrew Kaster 2023-09-15 18:27:46 -06:00 committed by Andrew Kaster
parent a243bc465f
commit ff0494c63b
Notes: sideshowbarker 2024-07-16 18:26:46 +09:00
9 changed files with 133 additions and 8 deletions

View File

@ -56,6 +56,11 @@
android:enabled="true"
android:exported="false"
android:process=":RequestServer" />
<service
android:name=".WebSocketService"
android:enabled="true"
android:exported="false"
android:process=":WebSocket" />
</application>
</manifest>

View File

@ -29,7 +29,18 @@
#include <WebContent/ConnectionFromClient.h>
#include <WebContent/PageHost.h>
static ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_service();
template<typename Client>
static ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int, int));
static ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_service()
{
return bind_service<Protocol::RequestClient>(&bind_request_server_java);
}
static ErrorOr<NonnullRefPtr<Protocol::WebSocketClient>> bind_web_socket_service()
{
return bind_service<Protocol::WebSocketClient>(&bind_web_socket_java);
}
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
{
@ -48,6 +59,9 @@ ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
auto request_server_client = TRY(bind_request_server_service());
Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client))));
auto web_socket_client = TRY(bind_web_socket_service());
Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create(move(web_socket_client))));
bool is_layout_test_mode = false;
Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode);
@ -66,7 +80,8 @@ ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
return event_loop.exec();
}
ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_service()
template<typename Client>
static ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int, int))
{
int socket_fds[2] {};
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
@ -81,12 +96,12 @@ ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_service()
int server_fd_passing_fd = fd_passing_socket_fds[1];
// NOTE: The java object takes ownership of the socket fds
bind_request_server_java(server_fd, server_fd_passing_fd);
(*bind_method)(server_fd, server_fd_passing_fd);
auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd));
TRY(socket->set_blocking(true));
auto new_client = TRY(try_make_ref_counted<Protocol::RequestClient>(move(socket)));
auto new_client = TRY(try_make_ref_counted<Client>(move(socket)));
new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
return new_client;

View File

@ -7,3 +7,4 @@
#pragma once
void bind_request_server_java(int ipc_socket, int fd_passing_socket);
void bind_web_socket_java(int ipc_socket, int fd_passing_socket);

View File

@ -11,6 +11,7 @@
jobject global_instance;
jclass global_class_reference;
jmethodID bind_request_server_method;
jmethodID bind_web_socket_method;
extern "C" JNIEXPORT void JNICALL
Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject thiz)
@ -27,6 +28,11 @@ Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject t
if (!method)
TODO();
bind_request_server_method = method;
method = env->GetMethodID(global_class_reference, "bindWebSocket", "(II)V");
if (!method)
TODO();
bind_web_socket_method = method;
}
void bind_request_server_java(int ipc_socket, int fd_passing_socket)
@ -34,3 +40,9 @@ void bind_request_server_java(int ipc_socket, int fd_passing_socket)
JavaEnvironment env(global_vm);
env.get()->CallVoidMethod(global_instance, bind_request_server_method, ipc_socket, fd_passing_socket);
}
void bind_web_socket_java(int ipc_socket, int fd_passing_socket)
{
JavaEnvironment env(global_vm);
env.get()->CallVoidMethod(global_instance, bind_web_socket_method, ipc_socket, fd_passing_socket);
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2021, Dex <dexes.ttp@gmail.com>
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/LexicalPath.h>
#include <Ladybird/Utilities.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/EventLoop.h>
#include <LibCore/LocalServer.h>
#include <LibCore/System.h>
#include <LibFileSystem/FileSystem.h>
#include <LibIPC/SingleServer.h>
#include <LibTLS/Certificate.h>
#include <WebSocket/ConnectionFromClient.h>
// FIXME: Share b/w RequestServer and WebSocket
ErrorOr<String> find_certificates(StringView serenity_resource_root)
{
auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root));
if (!FileSystem::exists(cert_path)) {
auto app_dir = LexicalPath::dirname(TRY(Core::System::current_executable_path()).to_deprecated_string());
cert_path = TRY(String::formatted("{}/cacert.pem", LexicalPath(app_dir).parent()));
if (!FileSystem::exists(cert_path))
return Error::from_string_view("Don't know how to load certs!"sv);
}
return cert_path;
}
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
{
// Ensure the certificates are read out here.
DefaultRootCACertificates::set_default_certificate_path(TRY(find_certificates(s_serenity_resource_root)));
[[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
Core::EventLoop event_loop;
auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket));
auto client = TRY(WebSocket::ConnectionFromClient::try_create(move(socket)));
client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket)));
return event_loop.exec();
}

View File

@ -35,6 +35,21 @@ class WebContentService : LadybirdServiceBase("WebContentService") {
)
}
private fun bindWebSocket(ipcFd: Int, fdPassingFd: Int)
{
val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir)
connector.onDisconnect = {
// FIXME: Notify impl that service is dead and might need restarted
Log.e(TAG, "RequestServer Died! :(")
}
// FIXME: Unbind this at some point maybe
bindService(
Intent(this, WebSocketService::class.java),
connector,
Context.BIND_AUTO_CREATE
)
}
external fun nativeInit()
companion object {

View File

@ -0,0 +1,21 @@
/**
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
package org.serenityos.ladybird
import android.os.Message
class WebSocketService : LadybirdServiceBase("WebSocketService") {
override fun handleServiceSpecificMessage(msg: Message): Boolean {
return false
}
companion object {
init {
System.loadLibrary("websocket")
}
}
}

View File

@ -1,8 +1,18 @@
set(SOURCES
"${SERENITY_SOURCE_DIR}/Userland/Services/WebSocket/ConnectionFromClient.cpp"
main.cpp
)
add_executable(WebSocketServer ${SOURCES})
if (ANDROID)
add_library(websocket SHARED
${SOURCES}
../Android/src/main/cpp/WebSocketService.cpp
../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp
../Utilities.cpp
)
else()
add_library(websocket STATIC ${SOURCES})
endif()
add_executable(WebSocketServer main.cpp)
target_link_libraries(WebSocketServer PRIVATE websocket)
set_target_properties(WebSocketServer PROPERTIES OUTPUT_NAME WebSocket)
target_link_libraries(WebSocketServer PRIVATE LibCore LibFileSystem LibIPC LibMain LibTLS LibWebSocket LibWebView)
target_link_libraries(websocket PUBLIC LibCore LibFileSystem LibIPC LibMain LibTLS LibWebSocket LibWebView)

View File

@ -45,7 +45,7 @@ macro(install_service_lib service)
endif()
endif()
endmacro()
foreach(service IN LISTS webcontent requestserver)
foreach(service IN LISTS webcontent requestserver websocket)
install_service_lib(${service})
endforeach()