Primeiros passos com a API no modo sandbox

Nesta página, você vai aprender a criar sua própria biblioteca C/C++ em sandbox com a API em sandbox (SAPI). Use-o como um guia junto com os exemplos e a documentação de código nos arquivos de cabeçalho.

Dependências do build

As seguintes dependências precisam ser instaladas no sistema:

  • Kernel do Linux com suporte para namespaces UTS, IPC, de usuário, PID e de rede
  • Cabeçalhos da API do espaço do usuário do Linux
  • Para compilar seu código: GCC 6 (preferencialmente versão 7 ou mais recente) ou Clang 7 (ou mais recente)
  • Para gerar automaticamente arquivos de cabeçalho: vinculações do Python do Clang
  • Python 3.5 ou posterior
  • Bazel versão 2.2.0 ou CMake versão 3.12 ou mais recente.
    • Somente CMake: GNU Make ou uma versão dos cabeçalhos da biblioteca libcap e uma ferramenta de build, como Ninja (recomendado).

Como usar o Bazel

O Bazel é o sistema de build recomendado e o mais fácil de integrar.

Nossa documentação usa o compilador Clang. Se você precisar de um conjunto de ferramentas específico (por exemplo, compilador, vinculador etc.), consulte a documentação do Bazel para saber como mudar o conjunto de ferramentas do compilador padrão.

Debian 10 (Buster)

Para instalar dependências de build:

echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \
  sudo tee /etc/apt/sources.list.d/bazel.list
wget -qO - https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install -qy build-essential linux-libc-dev bazel python3 \
  python3-pip libclang-dev
pip3 install clang

Gentoo

Opções de kernel necessárias:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

Para instalar dependências de build:

emerge dev-util/bazel dev-python/typing dev-python/clang-python

Como usar o CMake

O CMake é um sistema de metabuild de código aberto muito usado que gera arquivos de projeto para ferramentas de build como Ninja ou Make.

Debian 10 (Buster)

Para instalar dependências de build:

sudo apt-get install -qy build-essential linux-libc-dev cmake ninja-build \
  python3 python3-pip libclang-dev libcap-dev
pip3 install absl-py clang

Gentoo

Opções de kernel necessárias:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

Para instalar dependências de build:

emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \
dev-python/clang-python

Processo de desenvolvimento

Para isolar uma biblioteca C/C++, é preciso preparar dois itens para o projeto:

Talvez você já conheça a zlib dos exemplos do Sandbox2. Aqui, um programa inteiro (zpipe.c) foi colocado em sandbox. Nas etapas a seguir, você vai aprender a usar a SAPI para colocar a biblioteca zlib em sandbox e usar a biblioteca em sandbox.

1. Decidir quais funções são necessárias

Se você analisar o código do host zlib (main_zlib.cc), vai perceber que a funcionalidade da ferramenta é ler dados de stdin e usar a função deflate() do zlib para compactar os dados até que um marcador EOF seja lido. No total, o programa usa três funções da zlib:

  • deflateInit_(): para inicializar a compactação
  • deflate(): para realizar a operação de compactação no bloco de dados
  • deflateEnd(): para encerrar a compactação e liberar estruturas de dados alocadas dinamicamente

Em um exemplo real, você revisaria a biblioteca C/C++ e decidiria quais funções são necessárias. Uma estratégia possível é começar com o código do host e usar a biblioteca sem sandbox. Em seguida, em uma segunda etapa, você pode gerar a biblioteca em sandbox e adaptar o código do host para usar as chamadas de função em sandbox.

2. Escrever a regra de build sapi_library

Depois de identificar as três funções zlib necessárias da biblioteca zlib em sandbox, defina a regra de build no arquivo BUILD. A documentação da regra de build sapi_library pode ser encontrada na página Regras de build.

O snippet de código abaixo mostra a definição de sapi_library para o exemplo da SAPI zlib. Usando o atributo lib, o Bazel é instruído a procurar a biblioteca zlib no arquivo WORKSPACE.

sapi_library(
    name = "zlib-sapi",
    srcs = [],
    hdrs = [],
    functions = [
        "deflateInit_",
        "deflate",
        "deflateEnd",
    ],
    lib = "@net_zlib//:zlib",
    lib_name = "Zlib",
    namespace = "sapi::zlib",
)

Como resultado, a biblioteca zlib em sandbox é gerada. A saída é o objeto SAPI, que pode ser incluído no código do host e usado para se comunicar com a biblioteca em sandbox por chamadas de RPC. A política de sandbox usada neste exemplo é a padrão.

3. Escrever ou mudar o código do host

Agora é hora de incorporar a biblioteca SAPI gerada ao código do host.

Criar a sandbox

Use sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); para criar um objeto de sandbox.

Use sapi::zlib::ZlibApi api(&sandbox); para instanciar o objeto SAPI e, assim, disponibilizar as funções em sandbox para uso.

Usar tipos de SAPI

Os tipos SAPI são tipos especiais na forma de classes C++ que a SAPI fornece porque, às vezes, os tipos C regulares não funcionam.

O primeiro uso de um tipo de SAPI pode ser observado na declaração de strm, em que uma estrutura SAPI é usada: sapi::v::Struct<sapi::zlib::z_stream> strm;

O tipo de modelo (sapi::zlib::z_stream) é um bom exemplo de código gerado automaticamente pela regra de build.

Confira mais detalhes na página "Variáveis".

Fazer chamadas de API

Para fazer chamadas para defalteInit_, deflate ou deflateEnd, use o objeto SAPI. Se você decidir usar a abordagem "change", verifique se os parâmetros da função correspondem aos valores esperados.

Um exemplo de cada uma das chamadas no zlib example:

  • api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
        version.PtrBefore(), sizeof(sapi::zlib::z_stream));
  • api.deflate(strm.PtrBoth(), flush);
  • api.deflateEnd(strm.PtrBoth()).IgnoreError();

Como usar transações da SAPI

A SAPI isola o código do host da biblioteca em sandbox e dá ao autor da chamada a capacidade de reiniciar ou interromper solicitações problemáticas de processamento de dados. A transação SAPI vai um passo além e repete automaticamente os processos com falha.

Confira mais detalhes na página de transações da SAPI.

Exemplos

Em Exemplos, você encontra algumas bibliotecas já preparadas pela equipe da SAPI.