summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Jacobsen <kjetilja@gmail.com>2008-08-22 17:17:27 +0000
committerKjetil Jacobsen <kjetilja@gmail.com>2008-08-22 17:17:27 +0000
commit3b4b45d6d3aaf833f21013298a9e3c1f17c21575 (patch)
tree2c980b92422ad989af1c25df114745af978950b6
parentcebe685affd477792edb9b5d42a5a372d5133e80 (diff)
downloadpycurl-3b4b45d6d3aaf833f21013298a9e3c1f17c21575.tar.gz
OPENSOCKET support added
-rw-r--r--ChangeLog4
-rw-r--r--src/pycurl.c68
-rw-r--r--tests/test_socketopen.py17
3 files changed, 89 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 3a4600f..7be864f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,10 @@ Version 7.19.0 [requires libcurl-7.19.0 or better]
new 'reset' method on curl objects
(patch by Nick Pilon <npilon at oreilly.com>).
+ * Added support for OPENSOCKET callbacks.
+ See 'tests/test_opensocket.py' for example
+ usage (patch by Thomas Hunger <teh at camvine.com>).
+
Version 7.18.2
--------------
diff --git a/src/pycurl.c b/src/pycurl.c
index 40d74a8..1adeb1e 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -28,6 +28,7 @@
* Jim Patterson
* Yuhui H <eyecat at gmail.com>
* Nick Pilon <npilon at oreilly.com>
+ * Thomas Hunger <teh at camvine.org>
*
* See file README for license information.
*/
@@ -158,6 +159,7 @@ typedef struct {
PyObject *pro_cb;
PyObject *debug_cb;
PyObject *ioctl_cb;
+ PyObject *opensocket_cb;
/* file objects */
PyObject *readdata_fp;
PyObject *writedata_fp;
@@ -735,6 +737,7 @@ util_curl_new(void)
self->pro_cb = NULL;
self->debug_cb = NULL;
self->ioctl_cb = NULL;
+ self->opensocket_cb = NULL;
/* Set file object pointers to NULL by default */
self->readdata_fp = NULL;
@@ -1129,6 +1132,62 @@ header_callback(char *ptr, size_t size, size_t nmemb, void *stream)
return util_write_callback(1, ptr, size, nmemb, stream);
}
+/* curl_socket_t is just an int on unix/windows (with limitations that
+ * are not important here) */
+static curl_socket_t
+opensocket_callback(void *clientp, curlsocktype purpose,
+ struct curl_sockaddr *address)
+{
+ PyObject *arglist;
+ PyObject *result = NULL;
+ PyObject *fileno_result = NULL;
+ CurlObject *self;
+ PyThreadState *tmp_state;
+ int ret = CURL_SOCKET_BAD;
+
+ self = (CurlObject *)clientp;
+ tmp_state = get_thread_state(self);
+
+ PyEval_AcquireThread(tmp_state);
+ arglist = Py_BuildValue("(iii)", address->family, address->socktype, address->protocol);
+ if (arglist == NULL)
+ goto verbose_error;
+
+ result = PyEval_CallObject(self->opensocket_cb, arglist);
+
+ Py_DECREF(arglist);
+ if (result == NULL) {
+ goto verbose_error;
+ }
+
+ if (PyObject_HasAttrString(result, "fileno")) {
+ fileno_result = PyObject_CallMethod(result, "fileno", NULL);
+
+ if (fileno_result == NULL) {
+ ret = CURL_SOCKET_BAD;
+ goto verbose_error;
+ }
+ // normal operation:
+ if (PyInt_Check(fileno_result)) {
+ ret = dup(PyInt_AsLong(fileno_result));
+ goto done;
+ }
+ } else {
+ PyErr_SetString(ErrorObject, "Return value must be a socket.");
+ ret = CURL_SOCKET_BAD;
+ goto verbose_error;
+ }
+
+silent_error:
+done:
+ Py_XDECREF(result);
+ Py_XDECREF(fileno_result);
+ PyEval_ReleaseThread(tmp_state);
+ return ret;
+verbose_error:
+ PyErr_Print();
+ goto silent_error;
+}
static size_t
read_callback(char *ptr, size_t size, size_t nmemb, void *stream)
@@ -1960,6 +2019,7 @@ do_curl_setopt(CurlObject *self, PyObject *args)
const curl_progress_callback pro_cb = progress_callback;
const curl_debug_callback debug_cb = debug_callback;
const curl_ioctl_callback ioctl_cb = ioctl_callback;
+ const curl_opensocket_callback opensocket_cb = opensocket_callback;
switch(option) {
case CURLOPT_WRITEFUNCTION:
@@ -2010,6 +2070,13 @@ do_curl_setopt(CurlObject *self, PyObject *args)
curl_easy_setopt(self->handle, CURLOPT_IOCTLFUNCTION, ioctl_cb);
curl_easy_setopt(self->handle, CURLOPT_IOCTLDATA, self);
break;
+ case CURLOPT_OPENSOCKETFUNCTION:
+ Py_INCREF(obj);
+ ZAP(self->opensocket_cb);
+ self->opensocket_cb = obj;
+ curl_easy_setopt(self->handle, CURLOPT_OPENSOCKETFUNCTION, opensocket_cb);
+ curl_easy_setopt(self->handle, CURLOPT_OPENSOCKETDATA, self);
+ break;
default:
/* None of the function options were recognized, throw exception */
@@ -3638,6 +3705,7 @@ initpycurl(void)
insint_c(d, "FTPSSLAUTH", CURLOPT_FTPSSLAUTH);
insint_c(d, "IOCTLFUNCTION", CURLOPT_IOCTLFUNCTION);
insint_c(d, "IOCTLDATA", CURLOPT_IOCTLDATA);
+ insint_c(d, "OPENSOCKETFUNCTION", CURLOPT_OPENSOCKETFUNCTION);
insint_c(d, "FTP_ACCOUNT", CURLOPT_FTP_ACCOUNT);
insint_c(d, "IGNORE_CONTENT_LENGTH", CURLOPT_IGNORE_CONTENT_LENGTH);
insint_c(d, "COOKIELIST", CURLOPT_COOKIELIST);
diff --git a/tests/test_socketopen.py b/tests/test_socketopen.py
new file mode 100644
index 0000000..d3f0a62
--- /dev/null
+++ b/tests/test_socketopen.py
@@ -0,0 +1,17 @@
+import pycurl
+import StringIO
+import socket
+
+def socketopen(family, socktype, protocol):
+ print family, socktype, protocol
+ s = socket.socket(family, socktype, protocol)
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
+ return s
+
+sio = StringIO.StringIO()
+
+c = pycurl.Curl()
+c.setopt(pycurl.OPENSOCKETFUNCTION, socketopen)
+c.setopt(pycurl.URL, 'http://camvine.com')
+c.setopt(pycurl.WRITEFUNCTION, sio.write)
+c.perform()