=== modified file 'src/pycurl.c' --- src/pycurl.c 2008-04-23 09:22:23 +0000 +++ src/pycurl.c 2008-06-11 01:08:45 +0000 @@ -2445,6 +2445,36 @@ } +/* --------------- socket_action --------------- */ +static PyObject * +do_multi_socket_action(CurlMultiObject *self, PyObject *args) +{ + CURLMcode res; + curl_socket_t socket; + int ev_bitmask; + int running = -1; + + if (!PyArg_ParseTuple(args, "ii:socket_action", &socket, &ev_bitmask)) + return NULL; + if (check_multi_state(self, 1 | 2, "socket_action") != 0) { + return NULL; + } + /* Release global lock and start */ + self->state = PyThreadState_Get(); + assert(self->state != NULL); + Py_BEGIN_ALLOW_THREADS + + res = curl_multi_socket_action(self->multi_handle, socket, ev_bitmask, &running); + Py_END_ALLOW_THREADS + self->state = NULL; + + if (res != CURLM_OK) { + CURLERROR_MSG("multi_socket_action failed"); + } + /* Return a tuple with the result and the number of running handles */ + return Py_BuildValue("(ii)", (int)res, running); +} + /* --------------- socket_all --------------- */ static PyObject * @@ -2810,6 +2840,8 @@ static char co_multi_fdset_doc [] = "fdset() -> Tuple. Returns a tuple of three lists that can be passed to the select.select() method .\n"; static char co_multi_info_read_doc [] = "info_read([max_objects]) -> Tuple. Returns a tuple (number of queued handles, [curl objects]).\n"; static char co_multi_select_doc [] = "select([timeout]) -> Int. Returns result from doing a select() on the curl multi file descriptor with the given timeout.\n"; +static char co_multi_socket_action_doc [] = "socket_action(sockfd, ev_bitmask) -> Tuple. Returns result from doing a socket_action() on the curl multi file descriptor with the given timeout.\n"; +static char co_multi_socket_all_doc [] = "socket_all() -> Tuple. Returns result from doing a socket_all() on the curl multi file descriptor with the given timeout.\n"; static PyMethodDef curlshareobject_methods[] = { {"setopt", (PyCFunction)do_curlshare_setopt, METH_VARARGS, cso_setopt_doc}, @@ -2832,7 +2864,8 @@ {"fdset", (PyCFunction)do_multi_fdset, METH_NOARGS, co_multi_fdset_doc}, {"info_read", (PyCFunction)do_multi_info_read, METH_VARARGS, co_multi_info_read_doc}, {"perform", (PyCFunction)do_multi_perform, METH_NOARGS, NULL}, - {"socket_all", (PyCFunction)do_multi_socket_all, METH_NOARGS, NULL}, + {"socket_action", (PyCFunction)do_multi_socket_action, METH_VARARGS, co_multi_socket_action_doc}, + {"socket_all", (PyCFunction)do_multi_socket_all, METH_NOARGS, co_multi_socket_all_doc}, {"setopt", (PyCFunction)do_multi_setopt, METH_VARARGS, NULL}, {"timeout", (PyCFunction)do_multi_timeout, METH_NOARGS, NULL}, {"assign", (PyCFunction)do_multi_assign, METH_VARARGS, NULL}, @@ -3668,6 +3701,18 @@ insint(d, "GLOBAL_NOTHING", CURL_GLOBAL_NOTHING); insint(d, "GLOBAL_DEFAULT", CURL_GLOBAL_DEFAULT); + + /* constants for curl_multi_socket interface */ + insint(d, "CSELECT_IN", CURL_CSELECT_IN); + insint(d, "CSELECT_OUT", CURL_CSELECT_OUT); + insint(d, "CSELECT_ERR", CURL_CSELECT_ERR); + insint(d, "SOCKET_TIMEOUT", CURL_SOCKET_TIMEOUT); + insint(d, "POLL_NONE", CURL_POLL_NONE); + insint(d, "POLL_IN", CURL_POLL_IN); + insint(d, "POLL_OUT", CURL_POLL_OUT); + insint(d, "POLL_INOUT", CURL_POLL_INOUT); + insint(d, "POLL_REMOVE", CURL_POLL_REMOVE); + /* curl_lock_data: XXX do we need this in pycurl ??? */ /* curl_lock_access: XXX do we need this in pycurl ??? */ /* CURLSHcode: XXX do we need this in pycurl ??? */ === added file 'tests/test_multi_socket_select.py' --- tests/test_multi_socket_select.py 1970-01-01 00:00:00 +0000 +++ tests/test_multi_socket_select.py 2008-06-11 01:11:19 +0000 @@ -0,0 +1,105 @@ +#! /usr/bin/env python +# -*- coding: iso-8859-1 -*- +# vi:ts=4:et +# $Id: test_multi_socket.py,v 1.1 2006/11/10 15:03:05 kjetilja Exp $ + +import os, sys +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO +import pycurl +import select + +sockets = set() +timeout = 0 + +urls = ( + "http://curl.haxx.se", + "http://www.python.org", + "http://pycurl.sourceforge.net", +) + +# Read list of URIs from file specified on commandline +try: + urls = open(sys.argv[1], "rb").readlines() +except IndexError: + # No file was specified + pass + +# timer callback +def timer(msecs): + global timeout + timeout = msecs + print 'Timer callback msecs:', msecs + +# socket callback +def socket(event, socket, multi, data): + if event == pycurl.POLL_REMOVE: + print "Remove Socket %d"%socket + sockets.remove(socket) + else: + if socket not in sockets: + print "Add socket %d"%socket + sockets.add(socket) + print event, socket, multi, data + +# init +m = pycurl.CurlMulti() +m.setopt(pycurl.M_PIPELINING, 1) +m.setopt(pycurl.M_TIMERFUNCTION, timer) +m.setopt(pycurl.M_SOCKETFUNCTION, socket) +m.handles = [] +for url in urls: + c = pycurl.Curl() + # save info in standard Python attributes + c.url = url + c.body = StringIO() + c.http_code = -1 + m.handles.append(c) + # pycurl API calls + c.setopt(c.URL, c.url) + c.setopt(c.WRITEFUNCTION, c.body.write) + m.add_handle(c) + +# get data +num_handles = len(m.handles) + +while (pycurl.E_CALL_MULTI_PERFORM==m.socket_all()[0]): + pass + +timeout = m.timeout() + + +while True: + (rr, wr, er) = select.select(sockets,sockets,sockets,timeout/1000.0) + socketSet = set(rr+wr+er) + if socketSet: + for s in socketSet: + while True: + (ret,running) = m.socket_action(s,0) + if ret!=pycurl.E_CALL_MULTI_PERFORM: + break + else: + (ret,running) = m.socket_action(pycurl.SOCKET_TIMEOUT,0) + if running==0: + break + +# close handles +for c in m.handles: + # save info in standard Python attributes + c.http_code = c.getinfo(c.HTTP_CODE) + # pycurl API calls + m.remove_handle(c) + c.close() +m.close() + +# print result +for c in m.handles: + data = c.body.getvalue() + if 0: + print "**********", c.url, "**********" + print data + else: + print "%-53s http_code %3d, %6d bytes" % (c.url, c.http_code, len(data)) +