Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PicoRuby's Networking is Incomplete

Avatar for sylph01 sylph01
July 19, 2025
18

PicoRuby's Networking is Incomplete

2025/7/19 @ PicoRuby Overflow Kaigi
https://naniwarb.github.io/picorubyoverflowkaigi/

Avatar for sylph01

sylph01

July 19, 2025
Tweet

Transcript

  1. 4

  2. 何を使ってる? ハードウェア: CYW43439 TCP/IP, TLS: lwIP 暗号ライブラリ: Mbed TLS Pico

    SDK はこのへんが入っているだけ でなく、この間の連携をとってくれる 6
  3. TCP Client lwIP でTCP Client を実装するには以下のことをする: Protocol Control Block を作る

    recv , sent , err , poll のコールバックを作る recv : 受信したデータを扱う sent : 送信したデータを扱う(が何もしない) err : エラーを扱う(がほとんど何もしない) poll : idle な接続を扱う picoruby-net 以下 src/tcp.c 8
  4. static tcp_connection_state * TCPClient_new_connection(mrb_state *mrb, const net_request_t *req, net_response_t *res)

    { ... cs->pcb = altcp_new(NULL); altcp_recv(cs->pcb, TCPClient_recv_cb); altcp_sent(cs->pcb, TCPClient_sent_cb); altcp_err(cs->pcb, TCPClient_err_cb); altcp_poll(cs->pcb, TCPClient_poll_cb, 30); altcp_arg(cs->pcb, cs); ... return cs; } https:/ /github.com/picoruby/picoruby/blob/master/mrbgems/picoruby-net/src/tcp.c#L144-L162 9
  5. コールバックの例 static err_t TCPClient_recv_cb(void *arg, struct altcp_pcb *pcb, struct pbuf

    *pbuf, err_t err) arg に altcp_arg() の第2 引数で指定した値が渡ってくる PicoRuby のTCP 実装ではconnection state の構造体を作ってそれ を引き渡している pcb にはレスポンスに対応するProtocol Control Block が渡ってくる pbuf に受信した内容が入ってくる err には状態が渡ってくる。 ERR_OK でなければエラー 10
  6. TLS 対応 lwIP のApplication Layererd TCP(ALTCP) のおかげで少々の変更でTLS 対応可 能。 altcp_new()

    の代わりに altcp_tls_new() を呼ぶ altcp_tls_create_config_client() でTLS config を作る それを altcp_tls_new() の引数にする mbedtls_ssl_set_hostname() で接続するホスト名を記述 それ以外はすべて同じ! 11
  7. TCP Server の場合は? 一旦TLS は置いとくとして、 altcp_new() するところは同じ altcp_bind() でIP アドレスとポートにbind

    する altcp_listen() でlisten altcp_listen_with_backlog() を使うと複数接続をqueue の 形で受け付けることができる 12
  8. struct tcp_pcb *pcb = altcp_new(); // bind to 0.0.0.0:3000 err_t

    err = altcp_bind(pcb, IPADDR_TYPE_ANY, 3000); cyw43_arch_lwip_begin(); // a new PCB will be created and the original will be deallocated struct tcp_pcb *server_pcb = altcp_listen_with_backlog(pcb, 1); cyw43_arch_lwip_end(); altcp_arg(server_pcb, stuff_to_be_passed); altcp_accept(server_pcb, callback_for_accept); サーバーの初期化はこんな感じ 13
  9. static err_t callback_for_accept (void *arg, struct tcp_pcb *client_pcb, err_t err)

    { altcp_arg(client_pcb, stuff_to_be_passed); altcp_sent(client_pcb, callback_for_sent); altcp_recv(client_pcb, callback_for_recv); altcp_poll(client_pcb, callback_for_poll); altcp_err(client_pcb, callback_for_err); } ここまで来ると見覚えありますね。クライアントによるイベントに対応するコールバックを設定していきます 14
  10. TCP echo server recv のcallback 内でTCP Client の時と同様pbuf から値を読み込み それを

    altcp_write(pcb, buffer_to_be_sent, buffer_size, 0) で書き込み 完了すると sent のcallback が( 一応) 走る 15
  11. サーバー側のTLS は面倒 Application Layered TCP のおかげでTLS の追加自体は自明 ただしTLS 自体が面倒なので自明とは言ってない 証明書を持つ必要がある

    あと遅くなる。死ぬほど遅くなる これはRubyKaigi 2024 の発表のまとめでも言及した Pico の性能だとRSA 2048bit で6 秒くらいかかる 16
  12. だいたいこんなかんじ def respond(request) path = get_path(request) case path when '/'

    response = build_response(request.body) else ... end response end 20
  13. mrbc_funcall 改め mrbc_send //================================================================ /*! (BETA) Call any method of

    the object, but written by C. @param vm pointer to vm. @param v see below example. @param argc see below example. @param recv pointer to receiver. @param method_name method name. @param n_params num of params. >>> but written by C <<< https:/ /github.com/mrubyc/mrubyc/blob/master/src/class.c#L516-L585 22
  14. mruby/c ではRuby のメソッドを呼べな い https:/ /github.com/mrubyc/mrubyc/issues/234 The overhead of method

    calls is large. Because the Ruby methods will be executed by different VM, cannot pass arguments to the Ruby method. 23
  15. BLE ではどうしてる? 2023 年8 月時点でのcommit ではpacket callback をVM code にコンパイルし

    て動作させてた。 https:/ /github.com/picoruby/picoruby/commit/e9d98b5efe2bdfa0f532 aa04757c81e105d1bafb mrbc_run_mrblib(packet_callback_vm_code); packet_callback_vm_code = compile("BLE.instance&.packet_callback($_btstack_event_pac ket)"); 24
  16. BLE ではどうしてる? 現行ではpolling している。 while true (snip) packet = pop_packet

    packet_callback(packet) if packet heartbeat_callback if pop_heartbeat sleep_ms POLLING_UNIT_MS total_timeout_ms += POLLING_UNIT_MS end pop_packet と pop_heartbeat の中身がC 。 https:/ /github.com/picoruby/picoruby/blob/master/mrbgems/picoruby-ble/mrblib/ble.rb#L127-L138 25
  17. mruby/c じゃなくてmruby だった場合 は? send mrb_value mrb_f_send(mrb_state *mrb, mrb_value self)

    https:/ /github.com/mruby/mruby/blob/master/src/vm.c#L1073- L1077 mruby-metaprog mrbgem 以下にある C から呼ぶために使うかというとちょっと違う 27
  18. mruby/c じゃなくてmruby だった場合 は? mrb_funcall MRB_API mrb_value mrb_funcall(mrb_state *mrb, mrb_value

    self, const char *name, mrb_int argc, ...) https:/ /github.com/mruby/mruby/blob/master/src/vm.c#L558- L590 C からRuby コードを呼ぶこと想定だとこっち 28
  19. ところで: ESP32 のWiFi 対応? CYW43439 ではない石を使っているのでドライバ部分の流用が不可 能 https:/ /docs.espressif.com/projects/esp-idf/en/stable/esp32/api- guides/wifi.html

    cyw43_arch_lwip に依存してる部分がまるごと使えない がESP32 のWiFi チップのドライバ自体は存在してるのでlwIP と WiFi チップの間のやり取りまで面倒を見る必要はない 30
  20. ところで: ESP32 のWiFi 対応? lwIP 自体はESP32 のSDK に同梱されているがBSD Sockets API

    の利用 を推奨している https:/ /docs.espressif.com/projects/esp-idf/en/stable/esp32/api- guides/lwip.html ということはFreeRTOS task が走る いっそRaspberry Pi Pico W 側ももFreeRTOS に委ねることができ てしまえばBSD Socket API でなんとかできてしまうのでは? 31
  21. 正直なところ HTTP server with TLS だと遅すぎる ちゃんとセキュリティ保とうとするとZero 2 W とBLE

    で繋がって、 Zero 2 W がTLS しゃべるほうがよさそう 調べる限りBLE は認証はされるものの通信の秘匿まで必ずある ものではなさそう 33