mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Address review comments
This commit is contained in:
parent
192e443b7c
commit
a61421621c
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Copyright 2020 Google LLC
|
# Copyright 2020 Google LLC
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -13,13 +12,20 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
project(libuv_sandbox)
|
project(libuv_sandbox)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
# Add SAPI directories
|
||||||
|
add_subdirectory(
|
||||||
|
"${SAPI_ROOT}"
|
||||||
|
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||||
|
EXCLUDE_FROM_ALL
|
||||||
|
)
|
||||||
|
|
||||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/uv_wrapper")
|
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/uv_wrapper")
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
|
||||||
|
@ -28,33 +34,33 @@ add_custom_command(
|
||||||
|
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
|
||||||
COMMAND python3 "generator/wrapper_generator.py"
|
COMMAND "${SAPI_PYTHON3_EXECUTABLE}"
|
||||||
"libuv/include/uv.h"
|
"generator/wrapper_generator.py"
|
||||||
"${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.h"
|
"libuv/include/uv.h"
|
||||||
"${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.cc"
|
"${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.h"
|
||||||
|
"${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.cc"
|
||||||
|
|
||||||
COMMENT "Generate the wrapper header and source files"
|
COMMENT "Generate the wrapper header and source files"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
option(UV_SAPI_ENABLE_EXAMPLES "" ON)
|
option(SAPI_UV_ENABLE_EXAMPLES "" ON)
|
||||||
option(UV_SAPI_ENABLE_TESTS "" ON)
|
option(SAPI_UV_ENABLE_TESTS "" ON)
|
||||||
|
|
||||||
# Add callbacks used by examples and tests
|
# Add callbacks used by examples and tests
|
||||||
if (UV_SAPI_ENABLE_EXAMPLES OR UV_SAPI_ENABLE_TESTS)
|
if (SAPI_UV_ENABLE_EXAMPLES OR SAPI_UV_ENABLE_TESTS)
|
||||||
list(APPEND UV_SAPI_CALLBACKS
|
list(APPEND SAPI_UV_CALLBACKS
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/callbacks/callbacks.h"
|
"${CMAKE_CURRENT_SOURCE_DIR}/callbacks/callbacks.h"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/callbacks/callbacks.cc"
|
"${CMAKE_CURRENT_SOURCE_DIR}/callbacks/callbacks.cc"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Wrapper library including wrappers for all libuv methods and callbacks
|
# Wrapper library including wrappers for all libuv methods and callbacks
|
||||||
# The UV_SAPI_CALLBACKS variable should contain the absolute paths of
|
# The SAPI_UV_CALLBACKS variable should contain the absolute paths of
|
||||||
# all the files implementing the callbacks
|
# all the files implementing the callbacks
|
||||||
add_library(uv_wrapper_and_callbacks OBJECT
|
add_library(uv_wrapper_and_callbacks OBJECT
|
||||||
"${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.h"
|
"${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.h"
|
||||||
"${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.cc"
|
"${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.cc"
|
||||||
"${UV_SAPI_CALLBACKS}"
|
"${SAPI_UV_CALLBACKS}"
|
||||||
)
|
)
|
||||||
set_target_properties(uv_wrapper_and_callbacks
|
set_target_properties(uv_wrapper_and_callbacks
|
||||||
PROPERTIES LINKER_LANGUAGE C
|
PROPERTIES LINKER_LANGUAGE C
|
||||||
|
@ -66,13 +72,8 @@ target_link_libraries(uv_wrapper_and_callbacks uv_a)
|
||||||
|
|
||||||
# Setup Sandboxed API
|
# Setup Sandboxed API
|
||||||
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||||
set(SAPI_ENABLE_EXAMPLES ${UV_SAPI_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
|
set(SAPI_ENABLE_EXAMPLES ${SAPI_UV_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
|
||||||
set(SAPI_ENABLE_TESTS ${UV_SAPI_ENABLE_TESTS} CACHE BOOL "" FORCE)
|
set(SAPI_ENABLE_TESTS ${SAPI_UV_ENABLE_TESTS} CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(
|
|
||||||
"${SAPI_ROOT}"
|
|
||||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
|
||||||
EXCLUDE_FROM_ALL
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generate SAPI header
|
# Generate SAPI header
|
||||||
add_sapi_library(uv_sapi
|
add_sapi_library(uv_sapi
|
||||||
|
@ -374,8 +375,7 @@ add_sapi_library(uv_sapi
|
||||||
|
|
||||||
LIBRARY_NAME UV
|
LIBRARY_NAME UV
|
||||||
|
|
||||||
NAMESPACE ""
|
NAMESPACE uv
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Include generated SAPI header
|
# Include generated SAPI header
|
||||||
|
@ -384,11 +384,11 @@ target_include_directories(uv_sapi INTERFACE
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add examples
|
# Add examples
|
||||||
if (UV_SAPI_ENABLE_EXAMPLES)
|
if (SAPI_UV_ENABLE_EXAMPLES)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Add tests
|
# Add tests
|
||||||
if (UV_SAPI_ENABLE_TESTS)
|
if (SAPI_UV_ENABLE_TESTS)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# LibUV Sandbox
|
# LibUV Sandbox
|
||||||
|
|
||||||
This library is a sandboxed version of [LibUV](https://libuv.org/), implemented using Sandboxed API.
|
This library is a sandboxed version of [LibUV](https://libuv.org/), implemented
|
||||||
|
using Sandboxed API.
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
@ -10,14 +11,17 @@ git clone --recursive [URL to this repo]
|
||||||
```
|
```
|
||||||
The `--recursive` flag ensures that submodules are also cloned.
|
The `--recursive` flag ensures that submodules are also cloned.
|
||||||
|
|
||||||
Alternatively, if the repository has already been cloned but the submodules have not, these can be cloned using:
|
Alternatively, if the repository has already been cloned but the submodules have
|
||||||
|
not, these can be cloned using:
|
||||||
```
|
```
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
```
|
```
|
||||||
|
|
||||||
The full list of Sandboxed API dependencies can be found on [Sandboxed API Getting Started page](https://developers.google.com/sandboxed-api/docs/getting-started).
|
The full list of Sandboxed API dependencies can be found on
|
||||||
|
[Sandboxed API Getting Started page](https://developers.google.com/sandboxed-api/docs/getting-started).
|
||||||
|
|
||||||
The following commands, used from the current `libuv/` directory, build the library:
|
The following commands, used from the current `libuv/` directory, build the
|
||||||
|
library:
|
||||||
```
|
```
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
|
@ -27,36 +31,63 @@ cmake --build .
|
||||||
|
|
||||||
## Implementation details
|
## Implementation details
|
||||||
|
|
||||||
LibUV can't be directly sandboxed by Sandboxed API. Because of the size and complexity of the library, doing so creates some compilation errors and does not create the correct APIs for all methods. The solution for this issue is creating a wrapper library, whose methods (which can be sandboxed properly) internally call the original LibUV's methods.
|
LibUV can't be directly sandboxed by Sandboxed API. Because of the size and
|
||||||
|
complexity of the library, doing so creates some compilation errors and does not
|
||||||
|
create the correct APIs for all methods. The solution for this issue is creating
|
||||||
|
a wrapper library, whose methods (which can be sandboxed properly) internally
|
||||||
|
call the original LibUV's methods.
|
||||||
|
|
||||||
Using these wrapper methods is extremely simple, the only relevant difference is that they have a `sapi_` prefix before their names (e.g. `uv_loop_init` becomes `sapi_uv_loop_init`). The only exception is the variadic method `uv_loop_configure`. This has two wrappers, `sapi_uv_loop_configure` (with no additional parameters) and `sapi_uv_loop_configure_int` (with an additional `int` parameter). Currently, these are the only valid calls to the method in LibUV.
|
Using these wrapper methods is extremely simple, the only relevant difference is
|
||||||
|
that they have a `sapi_` prefix before their names (e.g. `uv_loop_init` becomes
|
||||||
|
`sapi_uv_loop_init`). The only exception is the variadic method
|
||||||
|
`uv_loop_configure`. This has two wrappers, `sapi_uv_loop_configure` (with no
|
||||||
|
additional parameters) and `sapi_uv_loop_configure_int` (with an additional
|
||||||
|
`int` parameter). Currently, these are the only valid calls to the method in
|
||||||
|
LibUV.
|
||||||
|
|
||||||
#### Wrapper generator
|
#### Wrapper generator
|
||||||
|
|
||||||
The wrapper is generated automatically by a Python script that is called by CMake at build time. This script can be found in the `generator` folder.
|
The wrapper is generated automatically by a Python script that is called by
|
||||||
|
CMake at build time. This script can be found in the `generator` folder.
|
||||||
|
|
||||||
#### Function pointers
|
#### Function pointers
|
||||||
|
|
||||||
The functions whose pointers will be passed to the library's methods (*callbacks*) can't be implemented in the files making use of the library, but must be in other files. These files must be compiled together with the library, and this is done by adding their absolute path to the CMake variable `UV_SAPI_CALLBACKS`.
|
The functions whose pointers will be passed to the library's methods
|
||||||
|
(*callbacks*) can't be implemented in the files making use of the library, but
|
||||||
|
must be in other files. These files must be compiled together with the library,
|
||||||
|
and this is done by adding their absolute path to the CMake variable
|
||||||
|
`SAPI_UV_CALLBACKS`.
|
||||||
|
|
||||||
The pointers can then be obtained using an `RPCChannel` object, as shown in the example `idle-basic.cc`.
|
The pointers can then be obtained using an `RPCChannel` object, as shown in the
|
||||||
|
example `idle-basic.cc`.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
The `examples` directory contains the sandboxed versions of example source codes taken from from [LibUV's User Guide](https://docs.libuv.org/en/v1.x/guide.html). More information about each example can be found in the examples' [README](examples/README.md).
|
The `examples` directory contains the sandboxed versions of example source codes
|
||||||
|
taken from from [LibUV's User Guide](https://docs.libuv.org/en/v1.x/guide.html).
|
||||||
|
More information about each example can be found in the examples'
|
||||||
|
[README](examples/README.md).
|
||||||
|
|
||||||
To build these examples when building the library, the CMake variable `UV_SAPI_ENABLE_EXAMPLES` must be set to `ON`. This enables Sandboxed API examples as well.
|
To build these examples when building the library, the CMake variable
|
||||||
|
`SAPI_UV_ENABLE_EXAMPLES` must be set to `ON`. This enables Sandboxed API
|
||||||
|
examples as well.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
The `tests` folder contains some test cases created using Google Test.
|
The `tests` folder contains some test cases created using Google Test.
|
||||||
|
|
||||||
To build these tests when building the library, the CMake variable `UV_SAPI_ENABLE_TESTS` must be set to `ON`. This enables Sandboxed API tests as well.
|
To build these tests when building the library, the CMake variable
|
||||||
|
`SAPI_UV_ENABLE_TESTS` must be set to `ON`. This enables Sandboxed API tests as
|
||||||
|
well.
|
||||||
|
|
||||||
## Policies
|
## Policies
|
||||||
|
|
||||||
Each example and test has an ad-hoc policy implemented on its own file. These policies can be used as references for pieces of code that perform similar operations. For example, the `helloworld.cc` example has a policy that only allows the strictly necessary syscalls for running a loop.
|
Each example and test has an ad-hoc policy implemented on its own file. These
|
||||||
|
policies can be used as references for pieces of code that perform similar
|
||||||
|
operations. For example, the `helloworld.cc` example has a policy that only
|
||||||
|
allows the strictly necessary syscalls for running a loop.
|
||||||
|
|
||||||
## Callbacks
|
## Callbacks
|
||||||
|
|
||||||
The `callbacks.h` and `callbacks.cc` files in the `callbacks` folder implement all the callbacks used by examples and tests.
|
The `callbacks.h` and `callbacks.cc` files in the `callbacks` folder implement
|
||||||
|
all the callbacks used by examples and tests.
|
||||||
|
|
|
@ -12,38 +12,36 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "callbacks.h"
|
#include "callbacks.h" // NOLINT(build/include)
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
size_t iterations = 0;
|
size_t g_iterations = 0;
|
||||||
size_t constexpr kMaxIterations = 1'000'000;
|
size_t constexpr kMaxIterations = 1'000'000;
|
||||||
|
static char g_buffer[1024];
|
||||||
|
static uv_buf_t g_iov;
|
||||||
|
|
||||||
// Stop the handle if the methods was called kMaxIterations times
|
// Stop the handle if the methods was called kMaxIterations times
|
||||||
void IdleCallback(uv_idle_t* handle) {
|
void IdleCallback(uv_idle_t* handle) {
|
||||||
iterations++;
|
++g_iterations;
|
||||||
if (iterations > kMaxIterations) {
|
if (g_iterations > kMaxIterations) {
|
||||||
std::cout << "IdleCallback was called " << kMaxIterations << " times"
|
std::cout << "IdleCallback was called " << kMaxIterations << " times"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
uv_idle_stop(handle);
|
uv_idle_stop(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char buffer[1024];
|
|
||||||
static uv_buf_t iov;
|
|
||||||
|
|
||||||
// Called after some chars have been written
|
// Called after some chars have been written
|
||||||
// As soon as writing of these bytes is completed, read more
|
// As soon as writing of these bytes is completed, read more
|
||||||
void OnWrite(uv_fs_t* req) {
|
void OnWrite(uv_fs_t* req) {
|
||||||
if (req->result < 0) {
|
if (req->result < 0) {
|
||||||
std::cerr << "Write error: " << uv_strerror(static_cast<int>(req->result))
|
std::cerr << "Write error: " << uv_strerror(static_cast<int>(req->result))
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
return;
|
||||||
} else {
|
|
||||||
// Start reading more after writing these bytes
|
|
||||||
uv_fs_read(uv_default_loop(), &read_req, open_req.result, &iov, 1, -1,
|
|
||||||
OnRead);
|
|
||||||
}
|
}
|
||||||
|
// Start reading more after writing these bytes
|
||||||
|
uv_fs_read(uv_default_loop(), &read_req, open_req.result, &g_iov, 1, -1,
|
||||||
|
OnRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after some chars have been read
|
// Called after some chars have been read
|
||||||
|
@ -51,16 +49,16 @@ void OnWrite(uv_fs_t* req) {
|
||||||
void OnRead(uv_fs_t* req) {
|
void OnRead(uv_fs_t* req) {
|
||||||
if (req->result < 0) {
|
if (req->result < 0) {
|
||||||
std::cerr << "Read error: " << uv_strerror(req->result) << std::endl;
|
std::cerr << "Read error: " << uv_strerror(req->result) << std::endl;
|
||||||
|
return;
|
||||||
} else if (req->result == 0) {
|
}
|
||||||
|
if (req->result == 0) {
|
||||||
// No more bytes left, close the loop
|
// No more bytes left, close the loop
|
||||||
uv_fs_t close_req;
|
uv_fs_t close_req;
|
||||||
uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL);
|
uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL);
|
||||||
|
|
||||||
} else if (req->result > 0) {
|
} else if (req->result > 0) {
|
||||||
// Start writing after reading some bytes
|
// Start writing after reading some bytes
|
||||||
iov.len = req->result;
|
g_iov.len = req->result;
|
||||||
uv_fs_write(uv_default_loop(), &write_req, 1, &iov, 1, -1, OnWrite);
|
uv_fs_write(uv_default_loop(), &write_req, 1, &g_iov, 1, -1, OnWrite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,18 +67,17 @@ void OnRead(uv_fs_t* req) {
|
||||||
void OnOpen(uv_fs_t* req) {
|
void OnOpen(uv_fs_t* req) {
|
||||||
if (req != &open_req) {
|
if (req != &open_req) {
|
||||||
std::cerr << "Open error: req != &open_req" << std::endl;
|
std::cerr << "Open error: req != &open_req" << std::endl;
|
||||||
|
return;
|
||||||
} else if (req->result < 0) {
|
}
|
||||||
|
if (req->result < 0) {
|
||||||
std::cerr << "Open error: " << uv_strerror(static_cast<int>(req->result))
|
std::cerr << "Open error: " << uv_strerror(static_cast<int>(req->result))
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
return;
|
||||||
} else {
|
|
||||||
// Initialize uv_buf_t buffer
|
|
||||||
iov = uv_buf_init(buffer, sizeof(buffer));
|
|
||||||
|
|
||||||
// Start reading after opening
|
|
||||||
uv_fs_read(uv_default_loop(), &read_req, req->result, &iov, 1, -1, OnRead);
|
|
||||||
}
|
}
|
||||||
|
// Initialize uv_buf_t g_buffer
|
||||||
|
g_iov = uv_buf_init(g_buffer, sizeof(g_buffer));
|
||||||
|
// Start reading after opening
|
||||||
|
uv_fs_read(uv_default_loop(), &read_req, req->result, &g_iov, 1, -1, OnRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the integer pointed by handle->data and increment it by one
|
// Get the integer pointed by handle->data and increment it by one
|
||||||
|
@ -88,6 +85,6 @@ void OnOpen(uv_fs_t* req) {
|
||||||
void TimerCallback(uv_timer_t* handle) {
|
void TimerCallback(uv_timer_t* handle) {
|
||||||
int* data = static_cast<int*>(
|
int* data = static_cast<int*>(
|
||||||
uv_handle_get_data(reinterpret_cast<uv_handle_t*>(handle)));
|
uv_handle_get_data(reinterpret_cast<uv_handle_t*>(handle)));
|
||||||
(*data)++;
|
++(*data);
|
||||||
uv_close(reinterpret_cast<uv_handle_t*>(handle), nullptr);
|
uv_close(reinterpret_cast<uv_handle_t*>(handle), nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,30 +12,27 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#ifndef CALLBACKS_H
|
#ifndef CALLBACKS_H_
|
||||||
#define CALLBACKS_H
|
#define CALLBACKS_H_
|
||||||
|
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
// idle-basic
|
// idle-basic
|
||||||
|
void IdleCallback(uv_idle_t* handle);
|
||||||
void IdleCallback(uv_idle_t *handle);
|
|
||||||
|
|
||||||
// uvcat
|
// uvcat
|
||||||
|
|
||||||
uv_fs_t open_req;
|
uv_fs_t open_req;
|
||||||
uv_fs_t read_req;
|
uv_fs_t read_req;
|
||||||
uv_fs_t write_req;
|
uv_fs_t write_req;
|
||||||
|
void OnWrite(uv_fs_t* req);
|
||||||
void OnWrite(uv_fs_t *req);
|
void OnRead(uv_fs_t* req);
|
||||||
void OnRead(uv_fs_t *req);
|
void OnOpen(uv_fs_t* req);
|
||||||
void OnOpen(uv_fs_t *req);
|
|
||||||
|
|
||||||
// test_callback
|
// test_callback
|
||||||
|
void TimerCallback(uv_timer_t* handle);
|
||||||
|
|
||||||
void TimerCallback(uv_timer_t *handle);
|
} // extern "C"
|
||||||
}
|
|
||||||
|
|
||||||
#endif // CALLBACKS_H
|
#endif // CALLBACKS_H_
|
||||||
|
|
|
@ -1,9 +1,23 @@
|
||||||
# LibUV Sandbox Examples
|
# LibUV Sandbox Examples
|
||||||
|
|
||||||
Each example in this folder is the sandboxed version of a code snippet from [LibUV's User Guide](https://docs.libuv.org/en/v1.x/guide.html). These examples perform some basic tasks using LibUV, and can be useful both to understand how to use LibUV Sandbox, but also to get an idea of how regular and sandboxed code compare to each other.
|
Each example in this folder is the sandboxed version of a code snippet from
|
||||||
|
[LibUV's User Guide](https://docs.libuv.org/en/v1.x/guide.html). These examples
|
||||||
|
perform some basic tasks using LibUV, and can be useful both to understand how
|
||||||
|
to use LibUV Sandbox, but also to get an idea of how regular and sandboxed code
|
||||||
|
compare to each other.
|
||||||
|
|
||||||
This is the list of examples:
|
This is the list of examples:
|
||||||
|
|
||||||
- **helloworld.cc**: sandboxed version of [helloworld/main.c](https://docs.libuv.org/en/v1.x/guide/basics.html#hello-world). It simply starts a loop that exits immediately. It shows how to run a simple loop in LibUV Sandbox.
|
- **helloworld.cc**: sandboxed version of
|
||||||
- **idle-basic.cc**: sandboxed version of [idle-basic/main.c](https://docs.libuv.org/en/v1.x/guide/basics.html#handles-and-requests). Creates an idle watcher that stops the loop after a certain number of iterations. It shows how a simple callback can be used in LibUV Sandbox.
|
[helloworld/main.c](https://docs.libuv.org/en/v1.x/guide/basics.html#hello-world).
|
||||||
- **uvcat.cc**: sandboxed version of [uvcat/main.c](http://docs.libuv.org/en/v1.x/guide/filesystem.html#reading-writing-files). Takes a single argument, the absolute path of a file, and prints its contents (it is a simplified version of the command line tootl `cat`). It shows how to manage various complex callbacks for opening, reading and writing files.
|
It simply starts a loop that exits immediately. It shows how to run a simple
|
||||||
|
loop in LibUV Sandbox.
|
||||||
|
- **idle-basic.cc**: sandboxed version of
|
||||||
|
[idle-basic/main.c](https://docs.libuv.org/en/v1.x/guide/basics.html#handles-and-requests).
|
||||||
|
Creates an idle watcher that stops the loop after a certain number of
|
||||||
|
iterations. It shows how a simple callback can be used in LibUV Sandbox.
|
||||||
|
- **uvcat.cc**: sandboxed version of
|
||||||
|
[uvcat/main.c](http://docs.libuv.org/en/v1.x/guide/filesystem.html#reading-writing-files).
|
||||||
|
Takes a single argument, the absolute path of a file, and prints its contents
|
||||||
|
(it is a simplified version of the command line tootl `cat`). It shows how to
|
||||||
|
manage various complex callbacks for opening, reading and writing files.
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "sandboxed_api/util/flag.h"
|
#include "sandboxed_api/util/flag.h"
|
||||||
#include "uv_sapi.sapi.h"
|
#include "uv_sapi.sapi.h"
|
||||||
|
|
||||||
class UVSapiHelloworldSandbox : public UVSandbox {
|
class UVSapiHelloworldSandbox : public uv::UVSandbox {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||||
sandbox2::PolicyBuilder*) override {
|
sandbox2::PolicyBuilder*) override {
|
||||||
|
@ -35,57 +35,51 @@ class UVSapiHelloworldSandbox : public UVSandbox {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
absl::Status HelloWorld() {
|
||||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
|
||||||
google::InitGoogleLogging(argv[0]);
|
|
||||||
|
|
||||||
absl::Status status;
|
|
||||||
|
|
||||||
// Initialize sandbox2 and sapi
|
// Initialize sandbox2 and sapi
|
||||||
UVSapiHelloworldSandbox sandbox;
|
UVSapiHelloworldSandbox sandbox;
|
||||||
status = sandbox.Init();
|
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||||
if (!status.ok()) {
|
uv::UVApi api(&sandbox);
|
||||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
|
||||||
}
|
|
||||||
UVApi api(&sandbox);
|
|
||||||
|
|
||||||
// Allocate memory for the uv_loop_t object
|
// Allocate memory for the uv_loop_t object
|
||||||
void* loop_voidptr;
|
void* loop_voidptr;
|
||||||
status = sandbox.rpc_channel()->Allocate(sizeof(uv_loop_t), &loop_voidptr);
|
SAPI_RETURN_IF_ERROR(
|
||||||
if (!status.ok()) {
|
sandbox.rpc_channel()->Allocate(sizeof(uv_loop_t), &loop_voidptr));
|
||||||
LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Allocate failed: " << status;
|
|
||||||
}
|
|
||||||
sapi::v::RemotePtr loop(loop_voidptr);
|
sapi::v::RemotePtr loop(loop_voidptr);
|
||||||
|
|
||||||
absl::StatusOr<int> return_code;
|
int return_code;
|
||||||
|
|
||||||
// Initialize loop
|
// Initialize loop
|
||||||
return_code = api.sapi_uv_loop_init(&loop);
|
SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_loop_init(&loop));
|
||||||
if (!return_code.ok()) {
|
if (return_code != 0) {
|
||||||
LOG(FATAL) << "sapi_uv_loop_init failed: " << return_code.status();
|
return absl::UnavailableError("uv_loop_init returned error " + return_code);
|
||||||
}
|
|
||||||
if (return_code.value() != 0) {
|
|
||||||
LOG(FATAL) << "uv_loop_init returned error " << return_code.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "The loop is about to quit" << std::endl;
|
std::cout << "The loop is about to quit" << std::endl;
|
||||||
|
|
||||||
// Run loop
|
// Run loop
|
||||||
return_code = api.sapi_uv_run(&loop, UV_RUN_DEFAULT);
|
SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_run(&loop, UV_RUN_DEFAULT));
|
||||||
if (!return_code.ok()) {
|
if (return_code != 0) {
|
||||||
LOG(FATAL) << "sapi_uv_run failed: " << return_code.status();
|
return absl::UnavailableError("uv_run returned error " + return_code);
|
||||||
}
|
|
||||||
if (return_code.value() != 0) {
|
|
||||||
LOG(FATAL) << "uv_run returned error " << return_code.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close loop
|
// Close loop
|
||||||
return_code = api.sapi_uv_loop_close(&loop);
|
SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_loop_close(&loop));
|
||||||
if (!return_code.ok()) {
|
if (return_code != 0) {
|
||||||
LOG(FATAL) << "sapi_uv_loop_close failed: " << return_code.status();
|
return absl::UnavailableError("uv_loop_close returned error " +
|
||||||
|
return_code);
|
||||||
}
|
}
|
||||||
if (return_code.value() != 0) {
|
|
||||||
LOG(FATAL) << "uv_loop_close returned error " << return_code.value();
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
|
google::InitGoogleLogging(argv[0]);
|
||||||
|
|
||||||
|
if (absl::Status status = HelloWorld(); !status.ok()) {
|
||||||
|
LOG(ERROR) << "HelloWorld failed: " << status.ToString();
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "sandboxed_api/util/flag.h"
|
#include "sandboxed_api/util/flag.h"
|
||||||
#include "uv_sapi.sapi.h"
|
#include "uv_sapi.sapi.h"
|
||||||
|
|
||||||
class UVSapiIdleBasicSandbox : public UVSandbox {
|
class UVSapiIdleBasicSandbox : public uv::UVSandbox {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||||
sandbox2::PolicyBuilder*) override {
|
sandbox2::PolicyBuilder*) override {
|
||||||
|
@ -36,88 +36,74 @@ class UVSapiIdleBasicSandbox : public UVSandbox {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
absl::Status IdleBasic() {
|
||||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
|
||||||
google::InitGoogleLogging(argv[0]);
|
|
||||||
|
|
||||||
absl::Status status;
|
|
||||||
|
|
||||||
// Initialize sandbox2 and sapi
|
// Initialize sandbox2 and sapi
|
||||||
UVSapiIdleBasicSandbox sandbox;
|
UVSapiIdleBasicSandbox sandbox;
|
||||||
status = sandbox.Init();
|
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||||
if (!status.ok()) {
|
uv::UVApi api(&sandbox);
|
||||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
|
||||||
}
|
|
||||||
UVApi api(&sandbox);
|
|
||||||
|
|
||||||
// Get remote pointer to the IdleCallback method
|
// Get remote pointer to the IdleCallback method
|
||||||
void* function_ptr;
|
void* function_ptr;
|
||||||
status = sandbox.rpc_channel()->Symbol("IdleCallback", &function_ptr);
|
SAPI_RETURN_IF_ERROR(
|
||||||
if (!status.ok()) {
|
sandbox.rpc_channel()->Symbol("IdleCallback", &function_ptr));
|
||||||
LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Symbol failed: " << status;
|
|
||||||
}
|
|
||||||
sapi::v::RemotePtr idle_callback(function_ptr);
|
sapi::v::RemotePtr idle_callback(function_ptr);
|
||||||
|
|
||||||
// Allocate memory for the uv_idle_t object
|
// Allocate memory for the uv_idle_t object
|
||||||
void* idle_voidptr;
|
void* idle_voidptr;
|
||||||
status = sandbox.rpc_channel()->Allocate(sizeof(uv_idle_t), &idle_voidptr);
|
SAPI_RETURN_IF_ERROR(
|
||||||
if (!status.ok()) {
|
sandbox.rpc_channel()->Allocate(sizeof(uv_idle_t), &idle_voidptr));
|
||||||
LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Allocate failed: " << status;
|
|
||||||
}
|
|
||||||
sapi::v::RemotePtr idler(idle_voidptr);
|
sapi::v::RemotePtr idler(idle_voidptr);
|
||||||
|
|
||||||
absl::StatusOr<int> return_code;
|
int return_code;
|
||||||
|
|
||||||
// Get default loop
|
// Get default loop
|
||||||
absl::StatusOr<void*> loop_voidptr = api.sapi_uv_default_loop();
|
SAPI_ASSIGN_OR_RETURN(void* loop_voidptr, api.sapi_uv_default_loop());
|
||||||
if (!loop_voidptr.ok()) {
|
sapi::v::RemotePtr loop(loop_voidptr);
|
||||||
LOG(FATAL) << "sapi_uv_default_loop failed: " << loop_voidptr.status();
|
|
||||||
}
|
|
||||||
sapi::v::RemotePtr loop(loop_voidptr.value());
|
|
||||||
|
|
||||||
// Initialize idler
|
// Initialize idler
|
||||||
return_code = api.sapi_uv_idle_init(&loop, &idler);
|
SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_idle_init(&loop, &idler));
|
||||||
if (!return_code.ok()) {
|
if (return_code != 0) {
|
||||||
LOG(FATAL) << "sapi_uv_idle_init failed: " << return_code.status();
|
return absl::UnavailableError("sapi_uv_idle_init returned error " +
|
||||||
}
|
return_code);
|
||||||
if (return_code.value() != 0) {
|
|
||||||
LOG(FATAL) << "sapi_uv_idle_init returned error " << return_code.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start idler
|
// Start idler
|
||||||
return_code = api.sapi_uv_idle_start(&idler, &idle_callback);
|
SAPI_ASSIGN_OR_RETURN(return_code,
|
||||||
if (!return_code.ok()) {
|
api.sapi_uv_idle_start(&idler, &idle_callback));
|
||||||
LOG(FATAL) << "sapi_uv_idle_start failed: " << return_code.status();
|
if (return_code != 0) {
|
||||||
}
|
return absl::UnavailableError("sapi_uv_idle_start returned error " +
|
||||||
if (return_code.value() != 0) {
|
return_code);
|
||||||
LOG(FATAL) << "sapi_uv_idle_start returned error " << return_code.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run loop
|
// Run loop
|
||||||
return_code = api.sapi_uv_run(&loop, UV_RUN_DEFAULT);
|
SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_run(&loop, UV_RUN_DEFAULT));
|
||||||
if (!return_code.ok()) {
|
if (return_code != 0) {
|
||||||
LOG(FATAL) << "sapi_uv_run failed: " << return_code.status();
|
return absl::UnavailableError("uv_run returned error " + return_code);
|
||||||
}
|
|
||||||
if (return_code.value() != 0) {
|
|
||||||
LOG(FATAL) << "uv_run returned error " << return_code.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close idler
|
// Close idler
|
||||||
sapi::v::NullPtr null_ptr;
|
sapi::v::NullPtr null_ptr;
|
||||||
status = api.sapi_uv_close(&idler, &null_ptr);
|
SAPI_RETURN_IF_ERROR(api.sapi_uv_close(&idler, &null_ptr));
|
||||||
if (!status.ok()) {
|
|
||||||
LOG(FATAL) << "sapi_uv_close failed: " << status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close loop
|
// Close loop
|
||||||
return_code = api.sapi_uv_loop_close(&loop);
|
SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_loop_close(&loop));
|
||||||
if (!return_code.ok()) {
|
|
||||||
LOG(FATAL) << "sapi_uv_loop_close failed: " << return_code.status();
|
|
||||||
}
|
|
||||||
// UV_EBUSY is accepted because it is the return code of uv_loop_close
|
// UV_EBUSY is accepted because it is the return code of uv_loop_close
|
||||||
// in the original example
|
// in the original example
|
||||||
if (return_code.value() != 0 && return_code.value() != UV_EBUSY) {
|
if (return_code != 0 && return_code != UV_EBUSY) {
|
||||||
LOG(FATAL) << "uv_loop_close returned error " << return_code.value();
|
return absl::UnavailableError("uv_loop_close returned error " +
|
||||||
|
return_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
|
google::InitGoogleLogging(argv[0]);
|
||||||
|
|
||||||
|
if (absl::Status status = IdleBasic(); !status.ok()) {
|
||||||
|
LOG(ERROR) << "IdleBasic failed: " << status.ToString();
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "sandboxed_api/util/flag.h"
|
#include "sandboxed_api/util/flag.h"
|
||||||
#include "uv_sapi.sapi.h"
|
#include "uv_sapi.sapi.h"
|
||||||
|
|
||||||
class UVSapiUVCatSandbox : public UVSandbox {
|
class UVSapiUVCatSandbox : public uv::UVSandbox {
|
||||||
public:
|
public:
|
||||||
UVSapiUVCatSandbox(std::string filename) : filename(filename) {}
|
UVSapiUVCatSandbox(std::string filename) : filename(filename) {}
|
||||||
|
|
||||||
|
@ -46,74 +46,62 @@ class UVSapiUVCatSandbox : public UVSandbox {
|
||||||
std::string filename;
|
std::string filename;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
absl::Status UVCat(std::string filearg) {
|
||||||
|
// Initialize sandbox2 and sapi
|
||||||
|
UVSapiUVCatSandbox sandbox(filearg);
|
||||||
|
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||||
|
uv::UVApi api(&sandbox);
|
||||||
|
|
||||||
|
// Get remote pointer to the OnOpen method
|
||||||
|
void* function_ptr;
|
||||||
|
SAPI_RETURN_IF_ERROR(sandbox.rpc_channel()->Symbol("OnOpen", &function_ptr));
|
||||||
|
sapi::v::RemotePtr on_open(function_ptr);
|
||||||
|
|
||||||
|
// Get remote pointer to the open_req variable
|
||||||
|
void* open_req_voidptr;
|
||||||
|
SAPI_RETURN_IF_ERROR(
|
||||||
|
sandbox.rpc_channel()->Symbol("open_req", &open_req_voidptr));
|
||||||
|
sapi::v::RemotePtr open_req(open_req_voidptr);
|
||||||
|
|
||||||
|
// Get default loop
|
||||||
|
SAPI_ASSIGN_OR_RETURN(void* loop_voidptr, api.sapi_uv_default_loop());
|
||||||
|
sapi::v::RemotePtr loop(loop_voidptr);
|
||||||
|
|
||||||
|
int return_code;
|
||||||
|
|
||||||
|
// Open file using the OnOpen callback (which will also read and print it)
|
||||||
|
sapi::v::ConstCStr filename(filearg.c_str());
|
||||||
|
SAPI_ASSIGN_OR_RETURN(
|
||||||
|
return_code, api.sapi_uv_fs_open(&loop, &open_req, filename.PtrBefore(),
|
||||||
|
O_RDONLY, 0, &on_open));
|
||||||
|
if (return_code != 0) {
|
||||||
|
return absl::UnavailableError("uv_fs_open returned error " + return_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run loop
|
||||||
|
SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_run(&loop, UV_RUN_DEFAULT));
|
||||||
|
if (return_code != 0) {
|
||||||
|
return absl::UnavailableError("uv_run returned error " + return_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup the request
|
||||||
|
SAPI_RETURN_IF_ERROR(api.sapi_uv_fs_req_cleanup(&open_req));
|
||||||
|
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
google::InitGoogleLogging(argv[0]);
|
google::InitGoogleLogging(argv[0]);
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
LOG(FATAL) << "wrong number of arguments (1 expected)";
|
LOG(ERROR) << "wrong number of arguments (1 expected)";
|
||||||
}
|
return EXIT_FAILURE;
|
||||||
std::string filename_str = argv[1];
|
|
||||||
|
|
||||||
absl::Status status;
|
|
||||||
|
|
||||||
// Initialize sandbox2 and sapi
|
|
||||||
UVSapiUVCatSandbox sandbox(filename_str);
|
|
||||||
status = sandbox.Init();
|
|
||||||
if (!status.ok()) {
|
|
||||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
|
||||||
}
|
|
||||||
UVApi api(&sandbox);
|
|
||||||
|
|
||||||
// Get remote pointer to the OnOpen method
|
|
||||||
void* function_ptr;
|
|
||||||
status = sandbox.rpc_channel()->Symbol("OnOpen", &function_ptr);
|
|
||||||
if (!status.ok()) {
|
|
||||||
LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Symbol failed: " << status;
|
|
||||||
}
|
|
||||||
sapi::v::RemotePtr on_open(function_ptr);
|
|
||||||
|
|
||||||
// Get remote pointer to the open_req variable
|
|
||||||
void* open_req_voidptr;
|
|
||||||
status = sandbox.rpc_channel()->Symbol("open_req", &open_req_voidptr);
|
|
||||||
if (!status.ok()) {
|
|
||||||
LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Symbol failed: " << status;
|
|
||||||
}
|
|
||||||
sapi::v::RemotePtr open_req(open_req_voidptr);
|
|
||||||
|
|
||||||
// Get default loop
|
|
||||||
absl::StatusOr<void*> loop_voidptr = api.sapi_uv_default_loop();
|
|
||||||
if (!loop_voidptr.ok()) {
|
|
||||||
LOG(FATAL) << "sapi_uv_default_loop failed: " << loop_voidptr.status();
|
|
||||||
}
|
|
||||||
sapi::v::RemotePtr loop(loop_voidptr.value());
|
|
||||||
|
|
||||||
absl::StatusOr<int> return_code;
|
|
||||||
|
|
||||||
// Open file using the OnOpen callback (which will also read and print it)
|
|
||||||
sapi::v::ConstCStr filename(filename_str.c_str());
|
|
||||||
return_code = api.sapi_uv_fs_open(&loop, &open_req, filename.PtrBefore(),
|
|
||||||
O_RDONLY, 0, &on_open);
|
|
||||||
if (!return_code.ok()) {
|
|
||||||
LOG(FATAL) << "sapi_uv_fs_open failed: " << return_code.status();
|
|
||||||
}
|
|
||||||
if (return_code.value() != 0) {
|
|
||||||
LOG(FATAL) << "uv_fs_open returned error " << return_code.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run loop
|
if (absl::Status status = UVCat(argv[1]); !status.ok()) {
|
||||||
return_code = api.sapi_uv_run(&loop, UV_RUN_DEFAULT);
|
LOG(ERROR) << "UVCat failed: " << status.ToString();
|
||||||
if (!return_code.ok()) {
|
return EXIT_FAILURE;
|
||||||
LOG(FATAL) << "sapi_uv_run failed: " << return_code.status();
|
|
||||||
}
|
|
||||||
if (return_code.value() != 0) {
|
|
||||||
LOG(FATAL) << "uv_run returned error " << return_code.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup the request
|
|
||||||
status = api.sapi_uv_fs_req_cleanup(&open_req);
|
|
||||||
if (!status.ok()) {
|
|
||||||
LOG(FATAL) << "sapi_uv_fs_req_cleanup failed: " << status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -11,14 +11,20 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""Script generating a wrapper API for LibUV."""
|
|
||||||
|
"""Script generating a wrapper API for LibUV.
|
||||||
|
.. note::
|
||||||
|
This scriptis highly specific to LibUV's source code
|
||||||
|
and does not generalize to any other library
|
||||||
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
from typing import List
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
def get_var_type(string):
|
def get_var_type(string : str) -> str:
|
||||||
"""Gets the type from an argument variable
|
"""Gets the type from an argument variable
|
||||||
(e.g. "int x" -> "int")
|
(e.g. "int x" -> "int")
|
||||||
"""
|
"""
|
||||||
|
@ -32,7 +38,7 @@ def get_var_type(string):
|
||||||
return " ".join(var.split(" ")[:-1]).strip()
|
return " ".join(var.split(" ")[:-1]).strip()
|
||||||
|
|
||||||
|
|
||||||
def get_var_name(string):
|
def get_var_name(string : str) -> str:
|
||||||
"""Gets the name from an argument variable
|
"""Gets the name from an argument variable
|
||||||
(e.g. "int x" -> "x")
|
(e.g. "int x" -> "x")
|
||||||
"""
|
"""
|
||||||
|
@ -50,7 +56,7 @@ def get_var_name(string):
|
||||||
return var.split(" ")[-1].strip()
|
return var.split(" ")[-1].strip()
|
||||||
|
|
||||||
|
|
||||||
def fix_method_type(string):
|
def fix_method_type(string : str) -> str:
|
||||||
"""Fixes the method type
|
"""Fixes the method type
|
||||||
(e.g. "const int*" -> "const void*")
|
(e.g. "const int*" -> "const void*")
|
||||||
"""
|
"""
|
||||||
|
@ -69,7 +75,7 @@ def fix_method_type(string):
|
||||||
return method_type
|
return method_type
|
||||||
|
|
||||||
|
|
||||||
def fix_argument(string):
|
def fix_argument(string : str) -> str:
|
||||||
"""Fixes an argument
|
"""Fixes an argument
|
||||||
(e.g. "const int* x" -> "const void* x")
|
(e.g. "const int* x" -> "const void* x")
|
||||||
"""
|
"""
|
||||||
|
@ -92,7 +98,7 @@ def fix_argument(string):
|
||||||
return arg_type + " " + arg_name
|
return arg_type + " " + arg_name
|
||||||
|
|
||||||
|
|
||||||
def fix_call_argument(string):
|
def fix_call_argument(string : str) -> str:
|
||||||
"""Fixes an argument in a call the orignal method
|
"""Fixes an argument in a call the orignal method
|
||||||
(e.g. "const int* x" -> "reinterpret_cast<const int*>(x)")
|
(e.g. "const int* x" -> "reinterpret_cast<const int*>(x)")
|
||||||
"""
|
"""
|
||||||
|
@ -113,14 +119,14 @@ def fix_call_argument(string):
|
||||||
return arg_name
|
return arg_name
|
||||||
|
|
||||||
|
|
||||||
def read_file(filename):
|
def read_file(filename : str) -> str:
|
||||||
"""Returns contents of filename as a string"""
|
"""Returns contents of filename as a string"""
|
||||||
|
|
||||||
file = open(filename, "r")
|
file = open(filename, "r")
|
||||||
return str(file.read())
|
return str(file.read())
|
||||||
|
|
||||||
|
|
||||||
def clean_file(text):
|
def clean_file(text : str) -> str:
|
||||||
"""Prepares the file for parsing
|
"""Prepares the file for parsing
|
||||||
In particular, removes comments and macros from text
|
In particular, removes comments and macros from text
|
||||||
Additionally, moves pointer asterisks next to its type
|
Additionally, moves pointer asterisks next to its type
|
||||||
|
@ -134,7 +140,7 @@ def clean_file(text):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_signatures(text):
|
def get_signatures(text : str) -> str:
|
||||||
"""Gets the signatures of all the methods in the header
|
"""Gets the signatures of all the methods in the header
|
||||||
.. note:: This method only works on a certain version of LibUV's header
|
.. note:: This method only works on a certain version of LibUV's header
|
||||||
"""
|
"""
|
||||||
|
@ -148,71 +154,78 @@ def get_signatures(text):
|
||||||
return zip(method_types, names, arguments_lists)
|
return zip(method_types, names, arguments_lists)
|
||||||
|
|
||||||
|
|
||||||
def write_method(method_type, name, arguments_list, header, source):
|
def append_method(method_type : str, name : str, arguments_list : List[str],
|
||||||
"""Writes the method to both the header and the source files"""
|
header : List[str], source : List[str]) -> None:
|
||||||
|
"""Writes the method to the header and the source list of lines"""
|
||||||
|
|
||||||
header.write(fix_method_type(method_type) + " sapi_" + name + "(" +
|
header.append(fix_method_type(method_type) + " sapi_" + name + "(" +
|
||||||
", ".join(map(fix_argument, arguments_list)) + ");\n\n")
|
", ".join(map(fix_argument, arguments_list)) + ");")
|
||||||
source.write(fix_method_type(method_type) + " sapi_" + name + "(" +
|
source.append(fix_method_type(method_type) + " sapi_" + name + "(" +
|
||||||
", ".join(map(fix_argument, arguments_list)) + ") {\n")
|
", ".join(map(fix_argument, arguments_list)) + ") {\n" +
|
||||||
source.write(" return " + name + "(" +
|
" return " + name + "(" +
|
||||||
", ".join(map(fix_call_argument, arguments_list)) + ");\n")
|
", ".join(map(fix_call_argument, arguments_list)) + ");\n" +
|
||||||
source.write("}\n\n")
|
"}")
|
||||||
|
|
||||||
|
|
||||||
def write_text(text, file):
|
def append_text(text : str, file : List[str]) -> None:
|
||||||
"""Writes text to file
|
"""Writes text to file list of lines
|
||||||
Useful for additional methods, includes, extern "C"...
|
Useful for additional methods, includes, extern "C"...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
file.write(text)
|
file.append(text)
|
||||||
|
|
||||||
|
|
||||||
def generate_wrapper():
|
def generate_wrapper() -> None:
|
||||||
"""Generates the wrapper"""
|
"""Generates the wrapper"""
|
||||||
|
|
||||||
|
header_file = open(sys.argv[2], "w")
|
||||||
|
source_file = open(sys.argv[3], "w")
|
||||||
|
|
||||||
text = read_file(sys.argv[1])
|
text = read_file(sys.argv[1])
|
||||||
text = clean_file(text)
|
text = clean_file(text)
|
||||||
signatures = get_signatures(text)
|
signatures = get_signatures(text)
|
||||||
|
|
||||||
header = open(sys.argv[2], "w")
|
header = []
|
||||||
source = open(sys.argv[3], "w")
|
source = []
|
||||||
|
|
||||||
write_text("#include <uv.h>\n\n", header)
|
append_text("#include <uv.h>", header)
|
||||||
write_text("extern \"C\" {\n\n", header)
|
append_text("extern \"C\" {", header)
|
||||||
write_text("#include \"" + os.path.abspath(header.name) + "\"\n\n", source)
|
append_text("#include \"" + os.path.abspath(header_file.name) + "\"", source)
|
||||||
|
|
||||||
for (method_type, name, arguments_list) in signatures:
|
for (method_type, name, arguments_list) in signatures:
|
||||||
# These wrapper methods are manually added at the end
|
# These wrapper methods are manually added at the end
|
||||||
if name in ("uv_once", "uv_loop_configure"):
|
if name in ("uv_once", "uv_loop_configure"):
|
||||||
continue
|
continue
|
||||||
write_method(method_type, name, arguments_list, header, source)
|
append_method(method_type, name, arguments_list, header, source)
|
||||||
|
|
||||||
# Add sapi_uv_once (uv_once uses a differnet kind of callback)
|
# Add sapi_uv_once (uv_once uses a differnet kind of callback)
|
||||||
write_text("void sapi_uv_once(void* guard, void (*callback)(void));\n\n",
|
append_text("void sapi_uv_once(void* guard, void (*callback)(void));",
|
||||||
header)
|
header)
|
||||||
write_text("void sapi_uv_once(void* guard, void (*callback)(void)) {\n" +
|
append_text("void sapi_uv_once(void* guard, void (*callback)(void)) {\n" +
|
||||||
" return uv_once(reinterpret_cast<uv_once_t*>(guard)," +
|
" return uv_once(reinterpret_cast<uv_once_t*>(guard)," +
|
||||||
"callback);\n" + "}\n\n", source)
|
"callback);\n" + "}", source)
|
||||||
|
|
||||||
# Add sapi_uv_loop_configure (uv_loop_configure is variadic)
|
# Add sapi_uv_loop_configure (uv_loop_configure is variadic)
|
||||||
write_text("int sapi_uv_loop_configure(void* loop, uv_loop_option option)" +
|
append_text("int sapi_uv_loop_configure(void* loop, uv_loop_option option)" +
|
||||||
";\n\n", header)
|
";", header)
|
||||||
write_text("int sapi_uv_loop_configure(void* loop, uv_loop_option option)" +
|
append_text("int sapi_uv_loop_configure(void* loop, uv_loop_option option)" +
|
||||||
" {\n return uv_loop_configure(" +
|
" {\n return uv_loop_configure(" +
|
||||||
"reinterpret_cast<uv_loop_t*>(loop), option);\n" + "}\n\n",
|
"reinterpret_cast<uv_loop_t*>(loop), option);\n" + "}",
|
||||||
source)
|
source)
|
||||||
|
|
||||||
# Add sapi_uv_loop_configure_int (uv_loop_configure is variadic)
|
# Add sapi_uv_loop_configure_int (uv_loop_configure is variadic)
|
||||||
write_text("int sapi_uv_loop_configure_int(void* loop, " +
|
append_text("int sapi_uv_loop_configure_int(void* loop, " +
|
||||||
"uv_loop_option option, int ap);\n\n", header)
|
"uv_loop_option option, int ap);", header)
|
||||||
write_text("int sapi_uv_loop_configure_int(void* loop, " +
|
append_text("int sapi_uv_loop_configure_int(void* loop, " +
|
||||||
"uv_loop_option option, int ap) {\n" +
|
"uv_loop_option option, int ap) {\n" +
|
||||||
" return uv_loop_configure(" +
|
" return uv_loop_configure(" +
|
||||||
"reinterpret_cast<uv_loop_t*>(loop), option, ap);\n}\n\n",
|
"reinterpret_cast<uv_loop_t*>(loop), option, ap);\n}",
|
||||||
source)
|
source)
|
||||||
|
|
||||||
write_text("} // extern \"C\"\n", header)
|
append_text("} // extern \"C\"\n", header)
|
||||||
|
|
||||||
|
header_file.write("\n\n".join(header))
|
||||||
|
source_file.write("\n\n".join(source))
|
||||||
|
|
||||||
|
|
||||||
generate_wrapper()
|
generate_wrapper()
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
#include "sandboxed_api/util/status_matchers.h"
|
#include "sandboxed_api/util/status_matchers.h"
|
||||||
#include "uv_sapi.sapi.h"
|
#include "uv_sapi.sapi.h"
|
||||||
|
|
||||||
class UVTestArraySapiSandbox : public UVSandbox {
|
namespace {
|
||||||
|
|
||||||
|
class UVTestArraySapiSandbox : public uv::UVSandbox {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||||
sandbox2::PolicyBuilder*) override {
|
sandbox2::PolicyBuilder*) override {
|
||||||
|
@ -40,12 +42,12 @@ class UVTestArray : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
sandbox_ = std::make_unique<UVTestArraySapiSandbox>();
|
sandbox_ = std::make_unique<UVTestArraySapiSandbox>();
|
||||||
ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk());
|
ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
|
||||||
api_ = std::make_unique<UVApi>(sandbox_.get());
|
api_ = std::make_unique<uv::UVApi>(sandbox_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<UVTestArraySapiSandbox> sandbox_;
|
std::unique_ptr<UVTestArraySapiSandbox> sandbox_;
|
||||||
std::unique_ptr<UVApi> api_;
|
std::unique_ptr<uv::UVApi> api_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(UVTestArray, LoadAvg) {
|
TEST_F(UVTestArray, LoadAvg) {
|
||||||
|
@ -65,3 +67,5 @@ TEST_F(UVTestArray, LoadAvg) {
|
||||||
ASSERT_GE(avg_buf[1], 0);
|
ASSERT_GE(avg_buf[1], 0);
|
||||||
ASSERT_GE(avg_buf[2], 0);
|
ASSERT_GE(avg_buf[2], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
#include "sandboxed_api/util/status_matchers.h"
|
#include "sandboxed_api/util/status_matchers.h"
|
||||||
#include "uv_sapi.sapi.h"
|
#include "uv_sapi.sapi.h"
|
||||||
|
|
||||||
class UVTestCallbackSapiSandbox : public UVSandbox {
|
namespace {
|
||||||
|
|
||||||
|
class UVTestCallbackSapiSandbox : public uv::UVSandbox {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||||
sandbox2::PolicyBuilder*) override {
|
sandbox2::PolicyBuilder*) override {
|
||||||
|
@ -40,8 +42,8 @@ class UVTestCallback : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
sandbox_ = std::make_unique<UVTestCallbackSapiSandbox>();
|
sandbox_ = std::make_unique<UVTestCallbackSapiSandbox>();
|
||||||
ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk());
|
ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
|
||||||
api_ = std::make_unique<UVApi>(sandbox_.get());
|
api_ = std::make_unique<uv::UVApi>(sandbox_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check sapi_uv_timer_init
|
// Check sapi_uv_timer_init
|
||||||
|
@ -87,7 +89,7 @@ class UVTestCallback : public ::testing::Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<UVTestCallbackSapiSandbox> sandbox_;
|
std::unique_ptr<UVTestCallbackSapiSandbox> sandbox_;
|
||||||
std::unique_ptr<UVApi> api_;
|
std::unique_ptr<uv::UVApi> api_;
|
||||||
|
|
||||||
static constexpr int kData = 1729;
|
static constexpr int kData = 1729;
|
||||||
};
|
};
|
||||||
|
@ -137,3 +139,5 @@ TEST_F(UVTestCallback, TimerCallback) {
|
||||||
UVDefaultLoop(&loop);
|
UVDefaultLoop(&loop);
|
||||||
UVLoopClose(loop.PtrNone());
|
UVLoopClose(loop.PtrNone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
#include "sandboxed_api/util/status_matchers.h"
|
#include "sandboxed_api/util/status_matchers.h"
|
||||||
#include "uv_sapi.sapi.h"
|
#include "uv_sapi.sapi.h"
|
||||||
|
|
||||||
class UVTestErrorSapiSandbox : public UVSandbox {
|
namespace {
|
||||||
|
|
||||||
|
class UVTestErrorSapiSandbox : public uv::UVSandbox {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||||
sandbox2::PolicyBuilder*) override {
|
sandbox2::PolicyBuilder*) override {
|
||||||
|
@ -37,8 +39,8 @@ class UVTestError : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
sandbox_ = std::make_unique<UVTestErrorSapiSandbox>();
|
sandbox_ = std::make_unique<UVTestErrorSapiSandbox>();
|
||||||
ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk());
|
ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
|
||||||
api_ = std::make_unique<UVApi>(sandbox_.get());
|
api_ = std::make_unique<uv::UVApi>(sandbox_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check sapi_uv_strerror on error
|
// Check sapi_uv_strerror on error
|
||||||
|
@ -67,7 +69,7 @@ class UVTestError : public ::testing::Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<UVTestErrorSapiSandbox> sandbox_;
|
std::unique_ptr<UVTestErrorSapiSandbox> sandbox_;
|
||||||
std::unique_ptr<UVApi> api_;
|
std::unique_ptr<uv::UVApi> api_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(UVTestError, ErrorMessage) {
|
TEST_F(UVTestError, ErrorMessage) {
|
||||||
|
@ -88,3 +90,5 @@ TEST_F(UVTestError, SystemError) {
|
||||||
UVTranslateSysError(UV_EACCES);
|
UVTranslateSysError(UV_EACCES);
|
||||||
UVTranslateSysError(0);
|
UVTranslateSysError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
#include "sandboxed_api/util/status_matchers.h"
|
#include "sandboxed_api/util/status_matchers.h"
|
||||||
#include "uv_sapi.sapi.h"
|
#include "uv_sapi.sapi.h"
|
||||||
|
|
||||||
class UVTestLoopSapiSandbox : public UVSandbox {
|
namespace {
|
||||||
|
|
||||||
|
class UVTestLoopSapiSandbox : public uv::UVSandbox {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||||
sandbox2::PolicyBuilder*) override {
|
sandbox2::PolicyBuilder*) override {
|
||||||
|
@ -39,8 +41,8 @@ class UVTestLoop : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
sandbox_ = std::make_unique<UVTestLoopSapiSandbox>();
|
sandbox_ = std::make_unique<UVTestLoopSapiSandbox>();
|
||||||
ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk());
|
ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
|
||||||
api_ = std::make_unique<UVApi>(sandbox_.get());
|
api_ = std::make_unique<uv::UVApi>(sandbox_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check sapi_uv_loop_init
|
// Check sapi_uv_loop_init
|
||||||
|
@ -69,7 +71,7 @@ class UVTestLoop : public ::testing::Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<UVTestLoopSapiSandbox> sandbox_;
|
std::unique_ptr<UVTestLoopSapiSandbox> sandbox_;
|
||||||
std::unique_ptr<UVApi> api_;
|
std::unique_ptr<uv::UVApi> api_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(UVTestLoop, InitLoop) {
|
TEST_F(UVTestLoop, InitLoop) {
|
||||||
|
@ -100,3 +102,5 @@ TEST_F(UVTestLoop, DefaultLoop) {
|
||||||
UVDefaultLoop(&loop);
|
UVDefaultLoop(&loop);
|
||||||
UVLoopClose(loop.PtrNone());
|
UVLoopClose(loop.PtrNone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
#include "sandboxed_api/util/status_matchers.h"
|
#include "sandboxed_api/util/status_matchers.h"
|
||||||
#include "uv_sapi.sapi.h"
|
#include "uv_sapi.sapi.h"
|
||||||
|
|
||||||
class UVTestOSSapiSandbox : public UVSandbox {
|
namespace {
|
||||||
|
|
||||||
|
class UVTestOSSapiSandbox : public uv::UVSandbox {
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||||
sandbox2::PolicyBuilder*) override {
|
sandbox2::PolicyBuilder*) override {
|
||||||
|
@ -43,12 +45,12 @@ class UVTestOS : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
sandbox_ = std::make_unique<UVTestOSSapiSandbox>();
|
sandbox_ = std::make_unique<UVTestOSSapiSandbox>();
|
||||||
ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk());
|
ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
|
||||||
api_ = std::make_unique<UVApi>(sandbox_.get());
|
api_ = std::make_unique<uv::UVApi>(sandbox_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<UVTestOSSapiSandbox> sandbox_;
|
std::unique_ptr<UVTestOSSapiSandbox> sandbox_;
|
||||||
std::unique_ptr<UVApi> api_;
|
std::unique_ptr<uv::UVApi> api_;
|
||||||
|
|
||||||
static constexpr size_t kBigBufLen = 4096;
|
static constexpr size_t kBigBufLen = 4096;
|
||||||
static constexpr size_t kSmallBufLen = 1;
|
static constexpr size_t kSmallBufLen = 1;
|
||||||
|
@ -131,3 +133,5 @@ TEST_F(UVTestOS, TmpDirSmall) {
|
||||||
// Test error code is as expected
|
// Test error code is as expected
|
||||||
ASSERT_EQ(error_code, expected_error_code);
|
ASSERT_EQ(error_code, expected_error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue
Block a user