-
Notifications
You must be signed in to change notification settings - Fork 1
/
curl-ev.sml
133 lines (114 loc) · 4.44 KB
/
curl-ev.sml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
structure CurlEv :
sig
type ev
type multi
type easy
val curl_ev: ev -> multi -> (easy * (easy * int -> unit) * int) -> unit
end =
struct
exception CurlEv of string
open Curl Curl.Const
open Ev
structure H = HashArrayLargeInt
type easy = Easy.curl
type multi = Multi.multi
fun curl_ev ev multi =
let
val hash_size = 100
val finishH = H.hash hash_size (* easy_int => finish *)
val timerH = H.hash hash_size (* easy_int => int *)
val multi_active = ref ~1
fun socket_action(socket, ev_bitmask) =
let
val active = Multi.socket_action(multi, socket, ev_bitmask)
fun info_read () =
let
fun doFinish easy result =
let
val easy_int = Multi.easy2int easy
val finish = valOf(H.sub(finishH, easy_int))
val timer_id_Option = H.sub(timerH, easy_int)
in
H.delete(timerH, easy_int);
H.delete(finishH, easy_int);
(case timer_id_Option of NONE => () | SOME timer_id => evTimerDelete ev timer_id);
finish(easy, result)
end
in
case Multi.info_read(multi) of
NONE => ()
| SOME (msg, easy, result) =>
if msg = CURLMSG_DONE
then (doFinish easy result; info_read () )
else raise (CurlEv ("I don't know what to do with message: " ^ Int.toString(msg)))
end
in
if (!multi_active) = active then () else ( multi_active := active; info_read () )
end
fun cb_timeout () = socket_action(CURL_SOCKET_TIMEOUT, 0)
val add_handle_timer_id = evTimerNew ev
fun add_handle(easy, finish:(Curl.Easy.curl * int -> unit), timeout) =
let
val easy_int = Multi.easy2int easy
val _ = H.update(finishH, easy_int, finish)
fun cb_big_timeout () =
case H.sub(timerH, easy_int) of
NONE => ()
| SOME timer_id =>
let
val finish = valOf(H.sub(finishH, easy_int))
in
evTimerDelete ev timer_id;
H.delete(timerH, easy_int);
H.delete(finishH, easy_int);
Multi.remove_handle(multi, easy);
finish (easy:Curl.Easy.curl, CURLE_OPERATION_TIMEDOUT)
end
in
Multi.add_handle(multi, easy);
evTimerAdd ev (add_handle_timer_id, Time.fromMilliseconds 1, cb_timeout);
if timeout = 0 then () else
let
val timer_id = evTimerNew ev
in
evTimerAdd ev (timer_id, Time.fromSeconds(Int.toLarge timeout), cb_big_timeout );
H.update(timerH, easy_int, timer_id)
end
end
val timerId = evTimerNew ev
fun cb_timer(multi, timeout_ms) =
let
val v =
if timeout_ms < 0 then Time.fromSeconds 10 else
(* if timeout_ms = 0 then Time.fromMicroseconds 1 else *)
if timeout_ms = 0 then Time.fromMilliseconds 1 else
Time.fromMilliseconds (Int.toLarge timeout_ms)
(*
https://curl.haxx.se/mail/lib-2019-03/0125.html
Because of this, 1 microseconds used for 0.
By the way, libev use 1 microsecond for 0.
C example from libcurl use 1 milliseconds for 0.
*)
in
evTimerAdd ev (timerId, v, cb_timeout);
1
end
fun cb_socket(easy, socket, poll) = (
if poll = CURL_POLL_IN orelse poll = CURL_POLL_INOUT
then evModify ev [evAdd (socket, evRead, (fn (_,_) => socket_action(socket, CURL_CSELECT_IN) ))]
else evModify ev [evDelete (socket, evRead)]
handle _ => (print ("Curl got exception for evDelete evRead on " ^ Int.toString socket ^ " fd.\n"); 0)
;
if poll = CURL_POLL_OUT orelse poll = CURL_POLL_INOUT
then evModify ev [evAdd (socket, evWrite, (fn (_,_) => socket_action(socket, CURL_CSELECT_OUT) ))]
else evModify ev [evDelete (socket, evWrite)]
handle _ => (print ("Curl got exception for evDelete evWrite on " ^ Int.toString socket ^ " fd.\n"); 0)
;
1
)
in
Multi.setopt_socket_cb(multi, cb_socket);
Multi.setopt_timer_cb(multi, cb_timer);
add_handle
end
end