Skip to content

Commit

Permalink
samples: modules: thrift: add samples for thrift module
Browse files Browse the repository at this point in the history
Here we add a client and server samples for the basic
"hello" service.

These samples are designed to be run by either Zephyr or
the host machine, interchangeably.

Additionally, there is a python version of the client
to demonstrate Thrift's cross-language capabilities.

This code was merged from the following repository
at the commit specified below, with minor formatting
and coding-style modifications.

https://github.com/zephyrproject-rtos/gsoc-2022-thrift
e12e014d295918cc5ba0b4c507d1bf595a2f539a

Signed-off-by: Chris Friedt <cfriedt@meta.com>
  • Loading branch information
cfriedt authored and stephanosio committed Feb 9, 2023
1 parent 2b8ea7d commit 3ea28b2
Show file tree
Hide file tree
Showing 21 changed files with 1,037 additions and 0 deletions.
61 changes: 61 additions & 0 deletions samples/modules/thrift/hello/client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright 2022 Meta
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(thrift_hello_server)

FILE(GLOB app_sources
src/*.cpp
)

include(${ZEPHYR_BASE}/modules/thrift/cmake/thrift.cmake)

set(generated_sources "")
set(gen_dir ${ZEPHYR_BINARY_DIR}/misc/generated/thrift_hello)
list(APPEND generated_sources ${gen_dir}/gen-cpp/hello_types.h)
list(APPEND generated_sources ${gen_dir}/gen-cpp/Hello.cpp)
list(APPEND generated_sources ${gen_dir}/gen-cpp/Hello.h)
list(APPEND app_sources ${generated_sources})

thrift(
app
cpp
:no_skeleton
${gen_dir}
${ZEPHYR_BASE}/samples/modules/thrift/hello/hello.thrift
""
${generated_sources}
)

target_sources(app PRIVATE ${app_sources})

# needed because std::iterator was deprecated with -std=c++17
target_compile_options(app PRIVATE -Wno-deprecated-declarations)

# convert .pem files to array data at build time
zephyr_include_directories(${gen_dir})

generate_inc_file_for_target(
app
${ZEPHYR_BASE}/samples/modules/thrift/hello/qemu-cert.pem
${gen_dir}/qemu_cert.pem.inc
)

generate_inc_file_for_target(
app
${ZEPHYR_BASE}/samples/modules/thrift/hello/qemu-key.pem
${gen_dir}/qemu_key.pem.inc
)

generate_inc_file_for_target(
app
${ZEPHYR_BASE}/samples/modules/thrift/hello/native-cert.pem
${gen_dir}/native_cert.pem.inc
)

generate_inc_file_for_target(
app
${ZEPHYR_BASE}/samples/modules/thrift/hello/native-key.pem
${gen_dir}/native_key.pem.inc
)
10 changes: 10 additions & 0 deletions samples/modules/thrift/hello/client/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2022 Meta

source "Kconfig.zephyr"

config THRIFT_COMPACT_PROTOCOL
bool "Use TCompactProtocol in samples"
depends on THRIFT
help
Enable this option to use TCompactProtocol in samples
44 changes: 44 additions & 0 deletions samples/modules/thrift/hello/client/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright 2022 Meta
# SPDX-License-Identifier: Apache-2.0

.PHONY: all clean

CXXFLAGS :=
CXXFLAGS += -std=c++17

GEN_DIR = gen-cpp
GENSRC = $(GEN_DIR)/Hello.cpp $(GEN_DIR)/Hello.h $(GEN_DIR)/hello_types.h
GENHDR = $(filter %.h, $(GENSRC))
GENOBJ = $(filter-out %.h, $(GENSRC:.cpp=.o))

THRIFT_FLAGS :=
THRIFT_FLAGS += $(shell pkg-config --cflags thrift)
THRIFT_FLAGS += -I$(GEN_DIR)
THRIFT_LIBS = $(shell pkg-config --libs thrift)

all: hello_client hello_client_compact hello_client_ssl hello_client_py.stamp

hello_client.stamp: ../hello.thrift
thrift --gen cpp:no_skeleton $<

$(GENSRC): hello_client.stamp
touch $@

%.o: %.cpp $(GENHDR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(THRIFT_FLAGS) -o $@ -c $<

hello_client: src/main.cpp $(GENOBJ) $(GENHDR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(THRIFT_FLAGS) -o $@ $< $(GENOBJ) $(THRIFT_LIBS)

hello_client_compact: src/main.cpp $(GENOBJ) $(GENHDR)
$(CXX) -DCONFIG_THRIFT_COMPACT_PROTOCOL=1 $(CPPFLAGS) $(CXXFLAGS) $(THRIFT_FLAGS) -o $@ $< $(GENOBJ) $(THRIFT_LIBS)

hello_client_ssl: src/main.cpp $(GENOBJ) $(GENHDR)
$(CXX) -DCONFIG_THRIFT_SSL_SOCKET=1 $(CPPFLAGS) $(CXXFLAGS) $(THRIFT_FLAGS) -o $@ $< $(GENOBJ) $(THRIFT_LIBS)

hello_client_py.stamp: ../hello.thrift
thrift --gen py $<
touch $@

clean:
rm -Rf hello_client hello_client_compact hello_client_ssl $(GEN_DIR) gen-py *.stamp
56 changes: 56 additions & 0 deletions samples/modules/thrift/hello/client/hello_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# Copyright (c) 2023, Meta
#
# SPDX-License-Identifier: Apache-2.0

"""Thrift Hello Client Sample
Connect to a hello service and demonstrate the
ping(), echo(), and counter() Thrift RPC methods.
Usage:
./hello_client.py [ip]
"""

import argparse
import sys
sys.path.append('gen-py')

from thrift.protocol import TBinaryProtocol
from thrift.transport import TTransport
from thrift.transport import TSocket
from hello import Hello


def parse_args():
parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument('--ip', default='192.0.2.1',
help='IP address of hello server')

return parser.parse_args()


def main():
args = parse_args()

transport = TSocket.TSocket(args.ip, 4242)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = Hello.Client(protocol)

transport.open()

client.ping()
client.echo('Hello, world!')

# necessary to mitigate unused variable warning with for i in range(5)
i = 0
while i < 5:
client.counter()
i = i + 1

transport.close()


if __name__ == '__main__':
main()
72 changes: 72 additions & 0 deletions samples/modules/thrift/hello/client/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# CONFIG_LIB_CPLUSPLUS Dependencies
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_NANO=n

# CONFIG_THRIFT Dependencies
CONFIG_CPP=y
CONFIG_STD_CPP17=y
CONFIG_CPP_EXCEPTIONS=y
CONFIG_EXTERNAL_LIBCPP=y
CONFIG_POSIX_API=y
CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETPAIR=y
CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_EVENTFD=y

CONFIG_THRIFT=y

CONFIG_TEST_RANDOM_GENERATOR=y
# pthread_cond_wait() triggers sentinel for some reason
CONFIG_STACK_SENTINEL=n

# Generic networking options
CONFIG_NETWORKING=y
CONFIG_NET_UDP=y
CONFIG_NET_TCP=y
CONFIG_NET_IPV6=n
CONFIG_NET_IPV4=y
CONFIG_NET_SOCKETS=y
CONFIG_POSIX_MAX_FDS=6
CONFIG_NET_CONNECTION_MANAGER=y

# Kernel options
CONFIG_ENTROPY_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_INIT_STACKS=y

# Logging
CONFIG_NET_LOG=y
CONFIG_LOG=y
CONFIG_NET_STATISTICS=y
CONFIG_PRINTK=y

# Network buffers
CONFIG_NET_PKT_RX_COUNT=16
CONFIG_NET_PKT_TX_COUNT=16
CONFIG_NET_BUF_RX_COUNT=64
CONFIG_NET_BUF_TX_COUNT=64
CONFIG_NET_CONTEXT_NET_PKT_POOL=y

# IP address options
CONFIG_NET_MAX_CONTEXTS=10

# Network application options and configuration
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_NEED_IPV6=n
CONFIG_NET_CONFIG_NEED_IPV4=y
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"

# Number of socket descriptors might need adjusting
# if there are more than 1 handlers defined.
CONFIG_POSIX_MAX_FDS=16

# Some platforms require relatively large stack sizes.
# This can be tuned per-board.
CONFIG_MAIN_STACK_SIZE=8192
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=8192
CONFIG_NET_TCP_WORKQ_STACK_SIZE=4096
CONFIG_NET_MGMT_EVENT_STACK_SIZE=4096
CONFIG_IDLE_STACK_SIZE=4096
CONFIG_NET_RX_STACK_SIZE=8192
16 changes: 16 additions & 0 deletions samples/modules/thrift/hello/client/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
sample:
description: Hello Thrift client sample
name: hello thrift client
common:
tags: thrift cpp sample
build_only: true
modules:
- thrift
platform_allow: mps2_an385 qemu_x86_64
tests:
sample.thrift.hello.server.binaryProtocol: {}
sample.thrift.hello.server.compactProtocol:
extra_configs:
- CONFIG_THRIFT_COMPACT_PROTOCOL=y
sample.thrift.hello.server.tlsTransport:
extra_args: OVERLAY_CONFIG="../overlay-tls.conf"
130 changes: 130 additions & 0 deletions samples/modules/thrift/hello/client/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright 2022 Young Mei
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifdef __ZEPHYR__
#include <zephyr/kernel.h>
#endif

#include <cstdlib>
#include <iostream>

#include <fcntl.h>

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/protocol/TCompactProtocol.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TSSLSocket.h>
#include <thrift/transport/TSocket.h>

#include "Hello.h"

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

#ifndef IS_ENABLED
#define IS_ENABLED(flag) flag
#endif

#ifndef CONFIG_THRIFT_COMPACT_PROTOCOL
#define CONFIG_THRIFT_COMPACT_PROTOCOL 0
#endif

#ifndef CONFIG_THRIFT_SSL_SOCKET
#define CONFIG_THRIFT_SSL_SOCKET 0
#endif

#ifdef __ZEPHYR__
int main(void)
#else
int main(int argc, char **argv)
#endif
{
std::string my_addr;

#ifdef __ZEPHYR__
my_addr = CONFIG_NET_CONFIG_PEER_IPV4_ADDR;
#else
if (IS_ENABLED(CONFIG_THRIFT_SSL_SOCKET)) {
if (argc != 5) {
printf("usage: %s <ip> <native-cert.pem> <native-key.pem> "
"<qemu-cert.pem>\n",
argv[0]);
return EXIT_FAILURE;
}
}

if (argc >= 2) {
my_addr = std::string(argv[1]);
} else {
my_addr = "192.0.2.1";
}
#endif

int port = 4242;
std::shared_ptr<TProtocol> protocol;
std::shared_ptr<TTransport> transport;
std::shared_ptr<TSSLSocketFactory> socketFactory;
std::shared_ptr<TTransport> trans;

if (IS_ENABLED(CONFIG_THRIFT_SSL_SOCKET)) {
const int port = 4242;
socketFactory = std::make_shared<TSSLSocketFactory>();
socketFactory->authenticate(true);

#ifdef __ZEPHYR__
static const char qemu_cert_pem[] = {
#include "qemu_cert.pem.inc"
};

static const char qemu_key_pem[] = {
#include "qemu_key.pem.inc"
};

static const char native_cert_pem[] = {
#include "native_cert.pem.inc"
};

socketFactory->loadCertificateFromBuffer(qemu_cert_pem);
socketFactory->loadPrivateKeyFromBuffer(qemu_key_pem);
socketFactory->loadTrustedCertificatesFromBuffer(native_cert_pem);
#else
socketFactory->loadCertificate(argv[2]);
socketFactory->loadPrivateKey(argv[3]);
socketFactory->loadTrustedCertificates(argv[4]);
#endif
trans = socketFactory->createSocket(my_addr, port);
} else {
trans = std::make_shared<TSocket>(my_addr, port);
}

transport = std::make_shared<TBufferedTransport>(trans);

if (IS_ENABLED(CONFIG_THRIFT_COMPACT_PROTOCOL)) {
protocol = std::make_shared<TCompactProtocol>(transport);
} else {
protocol = std::make_shared<TBinaryProtocol>(transport);
}

HelloClient client(protocol);

try {
transport->open();
client.ping();
std::string s;
client.echo(s, "Hello, world!");
for (int i = 0; i < 5; ++i) {
client.counter();
}

transport->close();
} catch (std::exception &e) {
printf("caught exception: %s\n", e.what());
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}
Loading

0 comments on commit 3ea28b2

Please sign in to comment.