-
Notifications
You must be signed in to change notification settings - Fork 130
/
multi.go
160 lines (140 loc) · 4.32 KB
/
multi.go
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// This file depends on functionality not available on Windows, hence we
// must skip it. https://github.com/andelf/go-curl/issues/48
// +build !windows
package curl
/*
#include <stdlib.h>
#include <curl/curl.h>
static CURLMcode curl_multi_setopt_long(CURLM *handle, CURLMoption option, long parameter) {
return curl_multi_setopt(handle, option, parameter);
}
static CURLMcode curl_multi_setopt_pointer(CURLM *handle, CURLMoption option, void *parameter) {
return curl_multi_setopt(handle, option, parameter);
}
static CURLMcode curl_multi_fdset_pointer(CURLM *handle,
void *read_fd_set,
void *write_fd_set,
void *exc_fd_set,
int *max_fd)
{
return curl_multi_fdset(handle, read_fd_set, write_fd_set, exc_fd_set, max_fd);
}
static CURLMsg *curl_multi_info_read_pointer(CURLM *handle, int *msgs_in_queue)
{
return curl_multi_info_read(handle, msgs_in_queue);
}
*/
import "C"
import (
"unsafe"
"syscall"
)
type CurlMultiError C.CURLMcode
type CurlMultiMsg C.CURLMSG
func (e CurlMultiError) Error() string {
// ret is const char*, no need to free
ret := C.curl_multi_strerror(C.CURLMcode(e))
return C.GoString(ret)
}
func newCurlMultiError(errno C.CURLMcode) error {
// cannot use C.CURLM_OK here, cause multi.h use a undefined emum num
if errno == 0 { // if nothing wrong
return nil
}
return CurlMultiError(errno)
}
func newCURLMessage(message *C.CURLMsg) (msg *CURLMessage){
if message == nil {
return nil
}
msg = new(CURLMessage)
msg.Msg = CurlMultiMsg(message.msg)
msg.Easy_handle = &CURL{handle: message.easy_handle}
msg.Data = message.data
return msg
}
type CURLM struct {
handle unsafe.Pointer
}
var dummy unsafe.Pointer
type CURLMessage struct {
Msg CurlMultiMsg
Easy_handle *CURL
Data [unsafe.Sizeof(dummy)]byte
}
// curl_multi_init - create a multi handle
func MultiInit() *CURLM {
p := C.curl_multi_init()
return &CURLM{p}
}
// curl_multi_cleanup - close down a multi session
func (mcurl *CURLM) Cleanup() error {
p := mcurl.handle
return newCurlMultiError(C.curl_multi_cleanup(p))
}
// curl_multi_perform - reads/writes available data from each easy handle
func (mcurl *CURLM) Perform() (int, error) {
p := mcurl.handle
running_handles := C.int(-1)
err := newCurlMultiError(C.curl_multi_perform(p, &running_handles))
return int(running_handles), err
}
// curl_multi_add_handle - add an easy handle to a multi session
func (mcurl *CURLM) AddHandle(easy *CURL) error {
mp := mcurl.handle
easy_handle := easy.handle
return newCurlMultiError(C.curl_multi_add_handle(mp, easy_handle))
}
// curl_multi_remove_handle - remove an easy handle from a multi session
func (mcurl *CURLM) RemoveHandle(easy *CURL) error {
mp := mcurl.handle
easy_handle := easy.handle
return newCurlMultiError(C.curl_multi_remove_handle(mp, easy_handle))
}
func (mcurl *CURLM) Timeout() (int, error) {
p := mcurl.handle
timeout := C.long(-1)
err := newCurlMultiError(C.curl_multi_timeout(p, &timeout))
return int(timeout), err
}
func (mcurl *CURLM) Setopt(opt int, param interface{}) error {
p := mcurl.handle
if param == nil {
return newCurlMultiError(C.curl_multi_setopt_pointer(p, C.CURLMoption(opt), nil))
}
switch {
// currently cannot support these option
// case MOPT_SOCKETFUNCTION, MOPT_SOCKETDATA, MOPT_TIMERFUNCTION, MOPT_TIMERDATA:
// panic("not supported CURLM.Setopt opt")
case opt >= C.CURLOPTTYPE_LONG:
val := C.long(0)
switch t := param.(type) {
case int:
val := C.long(t)
return newCurlMultiError(C.curl_multi_setopt_long(p, C.CURLMoption(opt), val))
case bool:
val = C.long(0)
if t {
val = C.long(1)
}
return newCurlMultiError(C.curl_multi_setopt_long(p, C.CURLMoption(opt), val))
}
}
panic("not supported CURLM.Setopt opt or param")
return nil
}
func (mcurl *CURLM) Fdset(rset, wset, eset *syscall.FdSet) (int, error) {
p := mcurl.handle
read := unsafe.Pointer(rset)
write := unsafe.Pointer(wset)
exc := unsafe.Pointer(eset)
maxfd := C.int(-1)
err := newCurlMultiError(C.curl_multi_fdset_pointer(p, read, write,
exc, &maxfd))
return int(maxfd), err
}
func (mcurl *CURLM) Info_read() (*CURLMessage, int) {
p := mcurl.handle
left := C.int(0)
return newCURLMessage(C.curl_multi_info_read_pointer(p, &left)), int(left)
}