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. から繰り返す。
中途半端だけど、寝る時間になったので終わり