libcurl の curl_multi_socket_action のメモ
Swift の URLSession の中で呼び出されている curl_multi_socket_action の動作を調べていたので、そのメモ。

基本的にはドキュメントを自分向けに意訳しただけ。
- multi handle を作る
URLSession._MultiHandleのrawHandleをCFURLSessionMultiHandleInitで初期化する箇所に該当する
- socket コールバックを
CURLMOPT_SOCKETFUNCTIONオプションと共にcurl_multi_setopで登録する。これによって、 multi handle のsocket_cbに指定したコールバックが登録される。URLSession._MultiHandlerではsetupCallbacks()内でのCFURLSession_multi_setopt_sf呼び出しに相当する。
- タイムアウトコールバックを
CURLMOPT_TIMERFUNCTIONオプションと共にcurl_multi_setopで登録する。このタイマーファンクションはtimeout_ms(というコールバックのパラメーター)が変更されたときに呼び出される。タイムアウトハンドラーに求められるのは 1. ループしないこと、 2.curl_multi_socket_actionまたはcurlmulti_performを呼び出すこと、 3.timeout_msが-1の場合はタイマーの削除/0の場合はcurl_multi_socket_actionまたはcurl_multi_performの呼び出しを行うことの3つであるURLSession._MultiHandlerではsetupCallbacks()内でのCFURLSession_multi_setopt_tf呼び出しに相当する。- 渡された
timeout_msをもって、_MultiHandle内のtimeoutSourceにタイムアウトを設定する
- easy handle を multi handle に追加する(
curl_multi_add_handle)URLSessionTaskにてresume関数が呼び出された際に、URLProtocolの内部状態を表すinternalStateが更新される- その setter にて
URLSessionのadd(handle:)関数に_EasyHandleが渡されて、curl_multi_add_handleが呼び出される
- libcurl が使っている ソケットを何らかの方法で管理する。 一般的には
glibやlibeventを使うらしい。 curl_multi_socket_action(渡すソケットはCURL_SOCKET_TIMEOUT定数) を呼び出すと、コールバックの呼び出しが始まるようになるURLSessionの場合は 3. にてDispatchSourceに設定したクロージャーが呼び出されることにより始まる(と思われる)
- イベントの発生を待つ
- イベントが発生した場合は、イベントの発生した socket に対して
curl_multi_socket_actionを呼び出す。タイムアウトが発生した場合は 6. から繰り返す。
中途半端だけど、寝る時間になったので終わり