うたカモ技術ブログ

Linux OpenWrt

OpenWrt   OpenWrt サンプルプログラム掲載! UBUS用C言語ライブラリ-libubus(sendコマンド実装)

post:     update: 

この記事で紹介するソースコードは自由に使っていただいて構いません。 アプリケーションの開発や自己学習にお役立て下さい。ただし、当ブログでは掲載するソースコードを流用・利用したことによる損害等につきましては 一切の責任を負いません。自己責任で利用お願いします。

今回は、C言語の自作アプリケーションにUBUSのsendコマンドと同等な処理を実装する方法について紹介します。

UBUSのsendコマンドは、イベント(JSON)を発行する処理です。 sendコマンドを利用すれば、UBUSのlistenコマンドなどでイベントをリッスンしているプロセスに通知を送ることができます。

これによって、イベント通知先プロセスが持つ特定処理の実行をトリガーすることができます。 (もちろん、ここら辺はイベント通知先プロセスの実装に依存するところではありますが。)

この記事では、そんなUBUSのsendコマンドを自作アプリケーション(例:ubus-sample03)に組み込むためのC言語実装について紹介します。

UBUS学習の参考サイト紹介
UBUSの学習に役立つサイトを紹介します。以下のサイトを読むことでコマンドの使用方法だけでなく、その実装方法についても理解できます。 私の記事と併用して読むとより理解に繋がると思います。

  1. What is UBUS?
  2. OpenWRT UBUS mechanism

目次

サンプルプログラム(ubus-sample03)のダウンロード

今回取り上げるubus-sample03のソースは私のGitHubリポジトリ(UtakamoStudyApps)にあります。

読者ご自身の環境で本アプリをビルド・インストールしてみたい方は私のGitHubリポジトリをダウンロードするか、 次のようにクローンしてください。

OpenWrt:~# git clone https://github.com/utakamo/UtakamoStudyApps.git

なお、ビルド方法に関してはGitHubのリポジトリ説明を参照するか、以下の記事をご覧ください。
【第 6 回】OpenWrt開発入門 自作アプリのパッケージ作成とインストール - パッケージ作成手順

【ラズパイ限定】このサイトからパッケージを入手してインストールする。

このサイトでは、ラズベリーパイ限定でパッケージを配布しています。 シリーズ別のパッケージを以下に掲載しますので、インストールしてみてください。

モデル パッケージ ハッシュ(SHA256)
Raspberry Pi1 ubus-sample03_1.0-1_arm_arm1176jzf-s_vfp.ipk 1eef8c8508336b493a5ace3c0b2d36b5879dd701fb0daee393f3b84a9b82c2d0
Raspberry Pi2 ubus-sample03_1.0-1_arm_cortex-a7_neon-vfpv4.ipk dbd7a3da9b5c23a6592d0acf921cdbefb2e4444fd9a3eed5b64d0dec70e0f1cb
Raspberry Pi3 ubus-sample03_1.0-1_aarch64_cortex-a53.ipk 9b77e902c4ed1a1c0e5e192928a509f5a66af451495663a9ea6eed0314880b09
Raspberry Pi4 ubus-sample03_1.0-1_aarch64_cortex-a72.ipk 823cf84edb649649f4f97e866df597099959d4a94b9828bf9841a5a8d8c0b179

次のコマンドを実行すると、パッケージをインストールすることができます。(以下はRaspberry Pi3用パッケージのインストール例です。)

root@OpenWrt:~# wget https://utakamo.com/repo/openwrt/raspi3/ubus/ubus-sample03_1.0-1_aarch64_cortex-a53.ipk
root@OpenWrt:~# opkg install ubus-sample03_1.0-1_aarch64_cortex-a53.ipk

ソースコードの紹介

ubus-sample03の初期化スクリプト

このサイトで紹介している他のサンプルプログラムと同じ内容です。

ubus-sample03はprocdによってシステムブート時に優先順位99番目(START=99)に起動され、シャットダウン時に 優先順位10番目(STOP=10)で終了するように設定しています。

#!/bin/sh /etc/rc.common

USE_PROCD=1
START=99
STOP=10

start_service() {
    echo 'ubus-sample03 start'
    procd_open_instance 'ubus-sample03'
    procd_set_param command /usr/bin/ubus-sample03
    procd_close_instance
}

ubus-sample03

今回はubus-sample03と命名したサンプルプログラムにsendコマンドと同等な処理を実装しました。

UBUSの各コマンド実装は、libubus.hに記述されていますので、これを利用して以下のように sendコマンドの処理をする関数(send_event)を定義しました。

#include <libubus.h>

void send_event(struct ubus_context *ctx);

int main()
{
	struct ubus_context *ctx = ubus_connect(NULL);

	send_event(ctx);
    ubus_free(ctx);

	return 0;
}

// Ubus send method
// This event can be received by running "ubus listen sample03-event".
void send_event(struct ubus_context *ctx) {
	struct blob_buf blob;
	blob_buf_init(&blob, 0);
	blobmsg_add_string(&blob, "message", "This is a sample event.");
	ubus_send_event(ctx, "sample03-event", blob.head);
}

send_event関数では、発行するイベントに任意のJSONデータを持たせたいので、libubox.hで定義されたJSONデータ作成用関数の blob_buf_init、blobmsg_add_string関数を使用して、"message":"This is a sample event." というJSONを作成しています。

上記のJSONを含める形で、ubus_send_event関数を使用してイベントのsample03-eventを発行します。 (もちろん、sample03-eventも厳密にはJSONのkeyなので、イベント単体でもJSONです。)

発行したイベントは窓口であるubusdに送られた後、ubusdを通してイベントの受信待ちをしているプロセスに通知されます。 (※ただし、イベントの受信待ちプロセスが特定イベントのみを受け取るようにubusdに要求していた場合、そのイベント以外のものはubusdでブロックされます。 要するに、ubus listen sample03-eventもしくはubus listenを実行しているかの違いです。)

以上がこのソースコードで実装した処理の詳細です。

次節では、実際にサンプルプログラムのubus-sample03を実行して結果を見てみます。

実行結果

前節で掲載したソースコードをビルドして作成したubus-sample03を実行して、その動作を見てみます。

最初にubus-sample03が発行するイベントを受信するプロセスを作成します。

UBUSの通信路上でやり取りされるイベント(JSON)を受信するためには、listenコマンドを以下のように使用します

root@OpenWrt:~# ubus listen &

次に、ubus-sample03を実行します。

root@OpenWrt:~# ubus-sample03

すると、ubus-sample03の実行で発行されたイベント(sample03-event)がubus listen &で生成されたプロセスに届き、 その結果が情報が出力されることが確認できます。

root@OpenWrt:~# ubus listen &
root@OpenWrt:~# ubus-sample03
{ "sample03-event": {"message":"This is a sample event."} }

このように、UBUSのsendコマンドを自作アプリケーションに実装すれば、UBUSを介してイベントの受信を待っている特定プロセスに 通知を行うことができます。

プロセス間通信を行って、複数プロセスが協調して動作することで実現されるサービスの実装などでsendコマンドやその組み込み実装が 役に立つと思います。

おわりに

今回はUBUSのsendコマンドと同等な処理のC言語実装について紹介しました。

複数のプロセス同士が連携する必要のあるケースで力を発揮する処理だと思いますので、 その特性を理解して使ってみると良いと思います。

参考文献