Skip to content

Commit f5831d3

Browse files
committed
Change the callback interface to comply with cgo pointer rules.
Fixes #43.
1 parent a9d0b09 commit f5831d3

File tree

3 files changed

+44
-101
lines changed

3 files changed

+44
-101
lines changed

c-callback.c

+4-30
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@
55

66
/* for OPT_HEADERFUNCTION */
77
size_t header_function( char *ptr, size_t size, size_t nmemb, void *ctx) {
8-
void *go_header_func = (void *)goGetCurlField((GoUintptr)ctx, "headerFunction");
9-
GoInterface *userdata = (GoInterface *)goGetCurlField((GoUintptr)ctx, "headerData");
10-
11-
if (userdata == NULL) {
12-
return goCallWriteFunctionCallback(go_header_func, ptr, size*nmemb, goNilInterface());
13-
}
14-
return goCallWriteFunctionCallback(go_header_func, ptr, size*nmemb, *userdata);
8+
return goCallHeaderFunction(ptr, size*nmemb, ctx);
159
}
1610

1711
void *return_header_function() {
@@ -21,13 +15,7 @@ void *return_header_function() {
2115

2216
/* for OPT_WRITEFUNCTION */
2317
size_t write_function( char *ptr, size_t size, size_t nmemb, void *ctx) {
24-
void *go_write_func = (void *)goGetCurlField((GoUintptr)ctx, "writeFunction");
25-
GoInterface *userdata = (GoInterface *)goGetCurlField((GoUintptr)ctx, "writeData");
26-
27-
if (userdata == NULL) {
28-
return goCallWriteFunctionCallback(go_write_func, ptr, size*nmemb, goNilInterface());
29-
}
30-
return goCallWriteFunctionCallback(go_write_func, ptr, size*nmemb, *userdata);
18+
return goCallWriteFunction(ptr, size*nmemb, ctx);
3119
}
3220

3321
void *return_write_function() {
@@ -36,13 +24,7 @@ void *return_write_function() {
3624

3725
/* for OPT_READFUNCTION */
3826
size_t read_function( char *ptr, size_t size, size_t nmemb, void *ctx) {
39-
void *go_read_func = (void *)goGetCurlField((GoUintptr)ctx, "readFunction");
40-
GoInterface *userdata = (GoInterface *)goGetCurlField((GoUintptr)ctx, "readData");
41-
42-
if (userdata == NULL) {
43-
return goCallReadFunctionCallback(go_read_func, ptr, size*nmemb, goNilInterface());
44-
}
45-
return goCallReadFunctionCallback(go_read_func, ptr, size*nmemb, *userdata);
27+
return goCallReadFunction(ptr, size*nmemb, ctx);
4628
}
4729

4830
void *return_read_function() {
@@ -52,15 +34,7 @@ void *return_read_function() {
5234

5335
/* for OPT_PROGRESSFUNCTION */
5436
int progress_function(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow) {
55-
void *go_progress_func = (void *)goGetCurlField((GoUintptr)ctx, "progressFunction");
56-
GoInterface *clientp = (GoInterface *)goGetCurlField((GoUintptr)ctx, "progressData");
57-
58-
if (clientp == NULL) {
59-
return goCallProgressCallback(go_progress_func, goNilInterface(),
60-
dltotal, dlnow, ultotal, ulnow);
61-
}
62-
return goCallProgressCallback(go_progress_func, *clientp,
63-
dltotal, dlnow, ultotal, ulnow);
37+
return goCallProgressFunction(dltotal, dlnow, ultotal, ulnow, ctx);
6438
}
6539

6640
void *return_progress_function() {

callback.go

+21-54
Original file line numberDiff line numberDiff line change
@@ -9,78 +9,45 @@ package curl
99
import "C"
1010

1111
import (
12-
"reflect"
1312
"unsafe"
1413
)
1514

16-
//export goGetCurlField
17-
func goGetCurlField(p uintptr, cname *C.char) uintptr {
18-
name := C.GoString(cname)
19-
curl := (*CURL)(unsafe.Pointer(p))
20-
switch name {
21-
case "readFunction":
22-
return reflect.ValueOf(curl.readFunction).Pointer()
23-
case "headerFunction":
24-
return reflect.ValueOf(curl.headerFunction).Pointer()
25-
case "writeFunction":
26-
return reflect.ValueOf(curl.writeFunction).Pointer()
27-
case "progressFunction":
28-
return reflect.ValueOf(curl.progressFunction).Pointer()
29-
case "headerData":
30-
return uintptr(unsafe.Pointer(curl.headerData))
31-
case "writeData":
32-
return uintptr(unsafe.Pointer(curl.writeData))
33-
case "readData":
34-
return uintptr(unsafe.Pointer(curl.readData))
35-
case "progressData":
36-
return uintptr(unsafe.Pointer(curl.progressData))
15+
//export goCallHeaderFunction
16+
func goCallHeaderFunction(ptr *C.char, size C.size_t, ctx unsafe.Pointer) uintptr {
17+
curl := (*CURL)(ctx)
18+
buf := C.GoBytes(unsafe.Pointer(ptr), C.int(size))
19+
if (*curl.headerFunction)(buf, curl.headerData) {
20+
return uintptr(size)
3721
}
38-
39-
warnf("Field not found: %s", name)
40-
return 0
41-
}
42-
43-
//export goNilInterface
44-
func goNilInterface() interface{} {
45-
return nil
22+
return C.CURL_WRITEFUNC_PAUSE
4623
}
4724

48-
// callback functions
49-
//export goCallWriteFunctionCallback
50-
func goCallWriteFunctionCallback(f *func([]byte, interface{}) bool,
51-
ptr *C.char,
52-
size C.size_t,
53-
userdata interface{}) uintptr {
25+
//export goCallWriteFunction
26+
func goCallWriteFunction(ptr *C.char, size C.size_t, ctx unsafe.Pointer) uintptr {
27+
curl := context_map[uintptr(ctx)]
5428
buf := C.GoBytes(unsafe.Pointer(ptr), C.int(size))
55-
ok := (*f)(buf, userdata)
56-
if ok {
29+
if (*curl.writeFunction)(buf, curl.writeData) {
5730
return uintptr(size)
5831
}
59-
//return uintptr(C.CURL_MAX_WRITE_SIZE + 1)
6032
return C.CURL_WRITEFUNC_PAUSE
6133
}
6234

63-
//export goCallProgressCallback
64-
func goCallProgressCallback(f *func(float64, float64, float64, float64, interface{}) bool,
65-
userdata interface{},
66-
dltotal, dlnow, ultotal, ulnow C.double) int {
67-
// fdltotal, fdlnow, fultotal, fulnow
68-
ok := (*f)(float64(dltotal), float64(dlnow), float64(ultotal), float64(ulnow), userdata)
69-
// non-zero va lue will cause libcurl to abort the transfer and return Error
70-
if ok {
35+
//export goCallProgressFunction
36+
func goCallProgressFunction(dltotal, dlnow, ultotal, ulnow C.double, ctx unsafe.Pointer) int {
37+
curl := context_map[uintptr(ctx)]
38+
if (*curl.progressFunction)(float64(dltotal), float64(dlnow),
39+
float64(ultotal), float64(ulnow),
40+
curl.progressData) {
7141
return 0
7242
}
7343
return 1
7444
}
7545

76-
//export goCallReadFunctionCallback
77-
func goCallReadFunctionCallback(f *func([]byte, interface{}) int,
78-
ptr *C.char,
79-
size C.size_t,
80-
userdata interface{}) uintptr {
81-
// TODO code cleanup
46+
//export goCallReadFunction
47+
func goCallReadFunction(ptr *C.char, size C.size_t, ctx unsafe.Pointer) uintptr {
48+
curl := context_map[uintptr(ctx)]
8249
buf := C.GoBytes(unsafe.Pointer(ptr), C.int(size))
83-
ret := (*f)(buf, userdata)
50+
ret := (*curl.readFunction)(buf, curl.readData)
8451
str := C.CString(string(buf))
8552
defer C.free(unsafe.Pointer(str))
8653
if C.memcpy(unsafe.Pointer(ptr), unsafe.Pointer(str), C.size_t(ret)) == nil {

easy.go

+19-17
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ import (
6666
"fmt"
6767
"mime"
6868
"path"
69-
"reflect"
7069
"unsafe"
7170
)
7271

@@ -105,28 +104,35 @@ type CURL struct {
105104
progressFunction *func(float64, float64, float64, float64, interface{}) bool
106105
fnmatchFunction *func(string, string, interface{}) int
107106
// callback datas
108-
headerData, writeData, readData, progressData, fnmatchData *interface{}
107+
headerData, writeData, readData, progressData, fnmatchData interface{}
109108
// list of C allocs
110109
mallocAllocs []*C.char
111110
}
112111

112+
var context_map = make(map[uintptr]*CURL)
113+
113114
// curl_easy_init - Start a libcurl easy session
114115
func EasyInit() *CURL {
115116
p := C.curl_easy_init()
116-
return &CURL{handle: p, mallocAllocs: make([]*C.char, 0)} // other field defaults to nil
117+
c := &CURL{handle: p, mallocAllocs: make([]*C.char, 0)} // other field defaults to nil
118+
context_map[uintptr(p)] = c
119+
return c
117120
}
118121

119122
// curl_easy_duphandle - Clone a libcurl session handle
120123
func (curl *CURL) Duphandle() *CURL {
121-
p := curl.handle
122-
return &CURL{handle: C.curl_easy_duphandle(p)}
124+
p := C.curl_easy_duphandle(curl.handle)
125+
c := &CURL{handle: p}
126+
context_map[uintptr(p)] = c
127+
return c
123128
}
124129

125130
// curl_easy_cleanup - End a libcurl easy session
126131
func (curl *CURL) Cleanup() {
127132
p := curl.handle
128133
C.curl_easy_cleanup(p)
129134
curl.MallocFreeAfter(0)
135+
delete(context_map, uintptr(p))
130136
}
131137

132138
// curl_easy_setopt - set options for a curl easy handle
@@ -140,16 +146,16 @@ func (curl *CURL) Setopt(opt int, param interface{}) error {
140146
switch {
141147
// not really set
142148
case opt == OPT_READDATA: // OPT_INFILE
143-
curl.readData = &param
149+
curl.readData = param
144150
return nil
145151
case opt == OPT_PROGRESSDATA:
146-
curl.progressData = &param
152+
curl.progressData = param
147153
return nil
148154
case opt == OPT_HEADERDATA: // also known as OPT_WRITEHEADER
149-
curl.headerData = &param
155+
curl.headerData = param
150156
return nil
151157
case opt == OPT_WRITEDATA: // OPT_FILE
152-
curl.writeData = &param
158+
curl.writeData = param
153159
return nil
154160

155161
case opt == OPT_READFUNCTION:
@@ -158,8 +164,7 @@ func (curl *CURL) Setopt(opt int, param interface{}) error {
158164

159165
ptr := C.return_read_function()
160166
if err := newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), ptr)); err == nil {
161-
return newCurlError(C.curl_easy_setopt_pointer(p, OPT_READDATA,
162-
unsafe.Pointer(reflect.ValueOf(curl).Pointer())))
167+
return newCurlError(C.curl_easy_setopt_pointer(p, OPT_READDATA, unsafe.Pointer(curl.handle)))
163168
} else {
164169
return err
165170
}
@@ -170,8 +175,7 @@ func (curl *CURL) Setopt(opt int, param interface{}) error {
170175

171176
ptr := C.return_progress_function()
172177
if err := newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), ptr)); err == nil {
173-
return newCurlError(C.curl_easy_setopt_pointer(p, OPT_PROGRESSDATA,
174-
unsafe.Pointer(reflect.ValueOf(curl).Pointer())))
178+
return newCurlError(C.curl_easy_setopt_pointer(p, OPT_PROGRESSDATA, unsafe.Pointer(curl.handle)))
175179
} else {
176180
return err
177181
}
@@ -182,8 +186,7 @@ func (curl *CURL) Setopt(opt int, param interface{}) error {
182186

183187
ptr := C.return_header_function()
184188
if err := newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), ptr)); err == nil {
185-
return newCurlError(C.curl_easy_setopt_pointer(p, OPT_HEADERDATA,
186-
unsafe.Pointer(reflect.ValueOf(curl).Pointer())))
189+
return newCurlError(C.curl_easy_setopt_pointer(p, OPT_HEADERDATA, unsafe.Pointer(curl.handle)))
187190
} else {
188191
return err
189192
}
@@ -194,8 +197,7 @@ func (curl *CURL) Setopt(opt int, param interface{}) error {
194197

195198
ptr := C.return_write_function()
196199
if err := newCurlError(C.curl_easy_setopt_pointer(p, C.CURLoption(opt), ptr)); err == nil {
197-
return newCurlError(C.curl_easy_setopt_pointer(p, OPT_WRITEDATA,
198-
unsafe.Pointer(reflect.ValueOf(curl).Pointer())))
200+
return newCurlError(C.curl_easy_setopt_pointer(p, OPT_WRITEDATA, unsafe.Pointer(curl.handle)))
199201
} else {
200202
return err
201203
}

0 commit comments

Comments
 (0)