Ejemplo n.º 1
0
def event_schedule(fd, timeout, user_callback):
    byref_timev = None
    if timeout is not None:
        timev = libevent.timeval()
        timev.tv_sec  = int(timeout)
        timev.tv_usec = int((timeout - int(timeout)) * 1000000)
        byref_timev = ctypes.byref(timev)

    event = libevent.event()
    byref_event = ctypes.byref(event)

    event_key = utils.set_userdata( (user_callback, byref_event, byref_timev) )
    libevent.event_set(byref_event, fd, libevent.EV_READ, event_callback_ptr, event_key)
    libevent.evtimer_add(byref_event, byref_timev)
    return lambda : utils.get_and_del_userdata(userdata_key)
Ejemplo n.º 2
0
def main_loop( bindings ):
    global base

    https = []
    for (host, port, application) in bindings:
        log.info("Binding to %s:%i" % (host,port))
        http = libevent.evhttp_start(host, port)
        if not http:
            log.critical("Bad host/port (host=%r port=%r) or address already in use" % (host,port))
            log.critical("QUITTING!")
            os.abort()
        libevent.evhttp_set_timeout(http,60) # minute, that's just for the http stuff
        vhostdata = {
            'application':application,
            'counter':0,
            'host':host,
            'port':port,
            'requests': {},
            'broken': 0,
            'cpu_time':0.0,
        }
        libevent.evhttp_set_gencb(http, new_request_callback_ptr, utils.set_userdata(vhostdata));
        vhosts.append(vhostdata)
        https.append(http)


    # The main libevent loop... Forever.
    libevent.event_dispatch()

    # end loop - id est Ctrl+c
    log.info("Quitting")
    for http in https:
        libevent.evhttp_free(http)
    libevent.event_base_free(base)

    utils.clear_ref()
    gc.collect()

    return returnvalue
Ejemplo n.º 3
0
    def schedule_fd(self, evreq, fd, timeout, event_flag):
        if getattr(fd, 'fileno', None):
            fd = fd.fileno()
        assert(isinstance(fd, int) or isinstance(fd, long))
        assert(fd >= 0)
        self.last_fd = fd

        byref_timev = None
        if timeout is not None:
            timev = libevent.timeval()
            timev.tv_sec  = int(timeout)
            timev.tv_usec = int((timeout - int(timeout)) * 1000000)
            byref_timev = ctypes.byref(timev)

        event = libevent.event()
        byref_event = ctypes.byref(event)

        # exit points: event (cleared  in handler), connection broken (cleared  in tail)
        self.event_key = utils.set_userdata( (evreq, self, byref_event) )
        libevent.event_set(byref_event, fd, event_flag, server.event_callback_ptr, self.event_key)
        libevent.evtimer_add(byref_event, byref_timev)
        self.suspended = True
        return ''
Ejemplo n.º 4
0
def root_handler(evreq, req, event_type, evt=None):
    content_length = 0
    chunks_number = 0
    response_dict = {'code':0, 'reason':''}
    request_closed  = False

    # dispatcher, new reqest or resume one?
    # head.
    if event_type == REQUEST_NEW:
        response_dict, chunked, iterable = req.start_wsgi_application()
        if not chunked:
            data = ''
            for data in iterable:
                break
            data = str(data)

            buf = libevent.evbuffer_new()
            for key, value in response_dict['headers']:
                libevent.evhttp_add_header(evreq.contents.output_headers, str(key), str(value))
            libevent.evbuffer_add(buf, data, len(data))
            libevent.evhttp_send_reply(evreq, response_dict['code'], response_dict['reason'], buf)
            libevent.evbuffer_free(buf)
            response_dict['transmitted'] = True
            req.content_length += len(data)
            req.chunks_number += 1

            content_length = len(data)
            chunks_number = 1
            del buf

    if event_type == REQUEST_CONTINUE:
        response_dict, chunked, iterable = req.continue_wsgi_application(True if evt and (evt & libevent.EV_TIMEOUT) else False)
        assert(chunked)

    # body.
    if event_type in [REQUEST_NEW, REQUEST_CONTINUE] and chunked:
        assert(getattr(iterable, '__iter__', None))
        iterator = getattr(iterable, '__iter__')()
        try:
            first_chunk = str(iterator.next())
        except StopIteration:
            first_chunk = None

        if not req.buf: # must be after first evaluation of iterable
            req.buf = libevent.evbuffer_new()
            for key, value in response_dict['headers']:
                if req.environ['SERVER_PROTOCOL'] == 'HTTP/1.1' and key == "Transfer-Encoding": # libevent automagically adds it's own transer-encoding header. f**k you libevent
                    continue
                libevent.evhttp_add_header(evreq.contents.output_headers, str(key), str(value))
            libevent.evhttp_send_reply_start(evreq, response_dict['code'], response_dict['reason'])
            response_dict['transmitted'] = True

            # exit points: connection broken (cleared in handler), end of request (cleared in tail)
            req.close_key = utils.set_userdata( (evreq, req) )
            libevent.evhttp_connection_set_closecb(evreq.contents.evcon, close_callback_ptr, req.close_key)

        if first_chunk:
            libevent.evbuffer_add(req.buf, first_chunk, len(first_chunk))
            libevent.evhttp_send_reply_chunk(evreq, req.buf)

            req.content_length += len(first_chunk)
            req.chunks_number += 1
            content_length += len(first_chunk)
            chunks_number  += 1

        # now transfer all the chunks
        for data_chunk in iterator:
            data_chunk = str(data_chunk)

            if not data_chunk: # can't really send empty data -> it means conn close
                continue

            # TODO: bug here, packets aren't on the wire just after evhttp_send_reply_chunk, and they should
            # TODO: this is not nice, but this is how http works in libevent, sorry.
            libevent.evbuffer_add(req.buf, data_chunk, len(data_chunk))
            libevent.evhttp_send_reply_chunk(evreq, req.buf)

            req.content_length += len(data_chunk)
            req.chunks_number += 1
            content_length += len(data_chunk)
            chunks_number  += 1

    # before closing
    req.update_cpu_time()
    # tail.
    if event_type == REQUEST_CLOSE or (chunked and req.is_closed()):
        if evreq.contents.evcon and evreq.contents.evcon.contents and evreq.contents.evcon.contents.closecb:
            libevent.evhttp_connection_set_closecb(evreq.contents.evcon, void_callback_ptr, None)

        if req.close_key:
            assert(event_type != REQUEST_CLOSE)
            utils.get_and_del_userdata(req.close_key)
            del req.close_key

        if event_type != REQUEST_CLOSE:
            libevent.evhttp_send_reply_end(evreq)
        else:
            assert(event_type == REQUEST_CLOSE)
            if evreq.contents.evcon:
                # BUG in libevent, memleak if conn is broken
                '''
                event = libevent.event()
                timeval = libevent.timeval()
                timeval.tv_sec  = 0
                timeval.tv_usec = 1
                byref_event = ctypes.byref(event)
                byref_timev = ctypes.byref(timeval)
                libevent.evtimer_set(byref_event, freeevcon_callback_ptr, utils.set_userdata( (evreq.contents.evcon, byref_event, byref_timev) )  )
                libevent.evtimer_add(byref_event, byref_timev)
                '''
                pass

        if req.buf:
            libevent.evbuffer_free(req.buf)
            del req.buf

        # free event, if scheduled:
        if req.event_key:
            assert(event_type == REQUEST_CLOSE)
            _, _,  byref_event = utils.get_and_del_userdata( req.event_key )
            libevent.event_del(byref_event)
            del byref_event
            del req.event_key

        req.close(con_broken=True if event_type == REQUEST_CLOSE else False)
        request_closed = True

    if event_type == REQUEST_NEW and not chunked:# cleanup single
        req.close(con_broken=False)
        # How the f**k to force closing connection here..., after sendig data
        #libevent.evhttp_request_free(evreq)
        #libevent.evhttp_connection_free(evreq.contents.evcon)

    log.debug('''%(host)s "%(method)s %(url)s %(http)s" %(status_code)i %(content_length)s/%(chunks_number)s (%(time).1fms) - %(event)s''' % {
        'method': req.environ['REQUEST_METHOD'],
        'url': req.get_url(),
        'http': req.environ['SERVER_PROTOCOL'],
        'status_code': response_dict['code'],
        'content_length': content_length,
        'chunks_number': chunks_number,
        'host': '%s:%i' % (req.environ['REMOTE_HOST'], req.environ['REMOTE_PORT']),
        'time': (req.now_cpu_time) * 1000, # in miliseconds
        'event': 'close' if request_closed else 'single' if not chunked else 'chunk',
        })

    return 1