gerkenjohannes | 19 Sep 14:40 2014
Picon

Re: Re: Assert fail in evhttp_connection_fail_ with req=0x00 on error=EVREQ_HTTP_TIMEOUT at http.c:691

I'm using the "master" from github.

The problem only occurs, when I set a timeout/retry for an https connection(to an server with port 443
closed). The segfault/assert-fail occurs, if I use EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST in
combination with the timeouts/retrys.

Testcase:
add the following to sample/https-client.c

struct timeval retry_timeout;
retry_timeout.tv_sec=5;
retry_timeout.tv_usec=0;
evhttp_connection_set_timeout(evcon,15);
evhttp_connection_set_retries(evcon,3);
evhttp_connection_set_initial_retry_tv(evcon,&retry_timeout);

execute: https_client -url https://libevent.org

output:

[warn] Epoll ADD(1) on fd 6 failed.  Old events were 0; read change was 1 (add); write change was 0 (none);
close change was 0 (none): Bad file descriptor
[debug] event_add: event: 0x25a5b30 (fd 6),  EV_WRITE  EV_TIMEOUT call 0x7f1942897ae4
[warn] Epoll ADD(4) on fd 6 failed.  Old events were 0; read change was 0 (none); write change was 1 (add);
close change was 0 (none): Bad file descriptor
[debug] event_process_active: event_callback 0x25a5c40, closure 3, call 0x7f1941fc8879
some request failed - no idea which one though!
socket error = Bad file descriptor (9)
 

(Continue reading)

jason | 19 Sep 10:10 2014

some connections of IOCP client are refused by IOCP server

I write a simple IOCP server, and a IOCP Client, and do the following test at the same machine.

IOCP Client creates 1000 buffer events to connect to IOCP server at start, but some of them are refused by IOCP server.

Error code is 10061.

 

// test_libevent_server.cpp : Defines the entry point for the console application.

//

 

#include "stdafx.h"

#include <string.h>

#include <errno.h>

#include <stdio.h>

#include <signal.h>

#ifndef WIN32

#include <netinet/in.h>

# ifdef _XOPEN_SOURCE_EXTENDED

#  include <arpa/inet.h>

# endif

#include <sys/socket.h>

#endif

 

#include <event2/bufferevent.h>

#include <event2/buffer.h>

#include <event2/listener.h>

#include <event2/util.h>

#include <event2/event.h>

#include <event2/thread.h>

#include <map>

 

static const char MESSAGE[] = "Hello, World!\n";

 

static const int PORT = 9995;

 

static void listener_cb(struct evconnlistener *, evutil_socket_t,

    struct sockaddr *, int socklen, void *);

static void conn_writecb(struct bufferevent *, void *);

static void conn_eventcb(struct bufferevent *, short, void *);

static void signal_cb(evutil_socket_t, short, void *);

 

int _tmain(int argc, _TCHAR* argv[])

{

 

   struct event_base *base;

   struct evconnlistener *listener;

   struct event *signal_event;

 

   struct sockaddr_in sin;

#ifdef WIN32

   WSADATA wsa_data;

   WSAStartup(0x0202, &wsa_data);

#endif

   event_config* pConfig = event_config_new();

   event_config_set_flag( pConfig, EVENT_BASE_FLAG_STARTUP_IOCP );

   evthread_use_windows_threads();

   base = event_base_new_with_config( pConfig );

   event_config_free( pConfig );

  

   if (!base) {

      fprintf(stderr, "Could not initialize libevent!\n");

      return 1;

   }

 

   memset(&sin, 0, sizeof(sin));

   sin.sin_family = AF_INET;

   sin.sin_port = htons(PORT);

 

   listener = evconnlistener_new_bind(base, listener_cb, (void *)base,

       LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,

       (struct sockaddr*)&sin,

       sizeof(sin));

 

   if (!listener) {

      fprintf(stderr, "Could not create a listener!\n");

      return 1;

   }

 

   signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);

 

   if (!signal_event || event_add(signal_event, NULL)<0) {

      fprintf(stderr, "Could not create/add a signal event!\n");

      return 1;

   }

 

   event_base_dispatch(base);

 

   evconnlistener_free(listener);

   event_free(signal_event);

   event_base_free(base);

 

   printf("done\n");

   return 0;

}

 

static void

listener_cb(struct evconnlistener *listener, evutil_socket_t fd,

    struct sockaddr *sa, int socklen, void *user_data)

{

   struct event_base *base = ( event_base* )user_data;

   struct bufferevent *bev;

 

   bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);

   if (!bev) {

      fprintf(stderr, "Error constructing bufferevent!");

      event_base_loopbreak(base);

      return;

   }

 

   static int s_iCount = 0;

   printf("count=%d,connected!\n",++s_iCount);

 

   bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);

   bufferevent_enable(bev, EV_WRITE);

   bufferevent_disable(bev, EV_READ);

 

   bufferevent_write(bev, MESSAGE, strlen(MESSAGE));

}

 

static void

conn_writecb(struct bufferevent *bev, void *user_data)

{

   struct evbuffer *output = bufferevent_get_output(bev);

   if (evbuffer_get_length(output) == 0) {

      static int s_iCount = 0;

      //printf("count=%d,flushed answer\n",++s_iCount);

      //bufferevent_free(bev);

   }

}

 

static void

conn_eventcb(struct bufferevent *bev, short events, void *user_data)

{

   if (events & BEV_EVENT_EOF) {

      static int s_iCount = 0;

      printf("count=%d,Connection closed.\n", ++s_iCount);

   } else if (events & BEV_EVENT_ERROR) {

      static int s_iCount = 0;

      printf("count=%d,Got an error on the connection: %s\n",

          ++s_iCount, strerror(errno));/*XXX win32*/

   }else if (events & BEV_EVENT_CONNECTED) {

      static int s_iCount = 0;

      printf("count=%d,connect!\n",++s_iCount);/*XXX win32*/

   }

   /* None of the other events can happen here, since we haven't enabled

   * timeouts */

   //bufferevent_free(bev);

}

 

static void

signal_cb(evutil_socket_t sig, short events, void *user_data)

{

   struct event_base *base = ( event_base* )user_data;

   struct timeval delay = { 2, 0 };

 

   printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");

 

   event_base_loopexit(base, &delay);

}

 

// test_libevent_Client.cpp : Defines the entry point for the console application.

//

 

#include "stdafx.h"

#include <string.h>

#include <errno.h>

#include <stdio.h>

#include <signal.h>

#ifndef WIN32

#include <netinet/in.h>

# ifdef _XOPEN_SOURCE_EXTENDED

#  include <arpa/inet.h>

# endif

#include <sys/socket.h>

#endif

 

#include <event2/bufferevent.h>

#include <event2/buffer.h>

#include <event2/listener.h>

#include <event2/util.h>

#include <event2/event.h>

#include <event2/thread.h>

 

static const char MESSAGE[] = "Hello, World!\n";

 

static const int PORT = 9995;

 

static void listener_cb(struct evconnlistener *, evutil_socket_t,

    struct sockaddr *, int socklen, void *);

static void conn_writecb(struct bufferevent *, void *);

static void conn_eventcb(struct bufferevent *, short, void *);

static void signal_cb(evutil_socket_t, short, void *);

 

int _tmain(int argc, _TCHAR* argv[])

{

   struct event_base *base;

   struct evconnlistener *listener;

   struct event *signal_event;

 

   struct sockaddr_in sin;

#ifdef WIN32

   WSADATA wsa_data;

   WSAStartup(0x0202, &wsa_data);

#endif

   event_config* pConfig = event_config_new();

   event_config_set_flag( pConfig, EVENT_BASE_FLAG_STARTUP_IOCP );

   evthread_use_windows_threads();

   base = event_base_new_with_config( pConfig );

   event_config_free( pConfig );

 

   if (!base) {

      fprintf(stderr, "Could not initialize libevent!\n");

      return 1;

   }

 

   memset(&sin, 0, sizeof(sin));

   sin.sin_family = AF_INET;

   sin.sin_addr.S_un.S_addr = htonl(0x7f000001);

   sin.sin_port = htons(PORT);

 

   const int NUM_BUFFER_EVENT = 2000;

   bufferevent* pBufferEvents[ NUM_BUFFER_EVENT ] = { 0 };

   for( int i = 0; i < NUM_BUFFER_EVENT; ++i )

   {

      pBufferEvents[ i ] = bufferevent_socket_new( base, -1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE );

 

      bufferevent_setcb( pBufferEvents[ i ], NULL, conn_writecb, conn_eventcb, NULL );

      bufferevent_enable( pBufferEvents[ i ], EV_WRITE | EV_READ );

 

      if( 0 != bufferevent_socket_connect(

         pBufferEvents[ i ],

         ( sockaddr* )&sin,

         sizeof( sin ) ) )

      {

         return 0;

      }

   }

 

   event_base_dispatch(base);

 

   for( int i = 0; i < NUM_BUFFER_EVENT; ++i )

   {

      if( pBufferEvents[ i ] )

      {

         bufferevent_free( pBufferEvents[ i ] );

      }

   }

 

   event_base_free(base);

 

   printf("done\n");

   return 0;

}

 

static void

listener_cb(struct evconnlistener *listener, evutil_socket_t fd,

    struct sockaddr *sa, int socklen, void *user_data)

{

   struct event_base *base = ( event_base* )user_data;

   struct bufferevent *bev;

 

   bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

   if (!bev) {

      fprintf(stderr, "Error constructing bufferevent!");

      event_base_loopbreak(base);

      return;

   }

   bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);

   bufferevent_enable(bev, EV_WRITE);

   bufferevent_disable(bev, EV_READ);

 

   bufferevent_write(bev, MESSAGE, strlen(MESSAGE));

}

 

static void

conn_writecb(struct bufferevent *bev, void *user_data)

{

   struct evbuffer *output = bufferevent_get_output(bev);

   if (evbuffer_get_length(output) == 0) {

      printf("flushed answer\n");

      //bufferevent_free(bev);

   }

}

 

static void

conn_eventcb(struct bufferevent *bev, short events, void *user_data)

{

   if (events & BEV_EVENT_EOF) {

      static int s_iCount = 0;

      printf("count=%d,Connection closed.\n", ++s_iCount);

   } else if (events & BEV_EVENT_ERROR) {

      static int s_iCount = 0;

      printf("count=%d,Got an error on the connection: %d\n",

          ++s_iCount, WSAGetLastError());/*XXX win32*/

   }else if (events & BEV_EVENT_CONNECTED) {

      static int s_iCount = 0;

      printf("count=%d,connect!\n",++s_iCount);/*XXX win32*/

   }

   /* None of the other events can happen here, since we haven't enabled

   * timeouts */

   //bufferevent_free(bev);

}

 

static void

signal_cb(evutil_socket_t sig, short events, void *user_data)

{

   struct event_base *base = ( event_base* )user_data;

   struct timeval delay = { 2, 0 };

 

   printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");

 

   event_base_loopexit(base, &delay);

}

 

Could you tell me why?

Topher LaFata | 17 Sep 21:19 2014

bufferevent_openssl_filter_new and event_base_free

Hello,

I am running into a problem where I am unable to properly free the event_base when using the bufferevent_openssl_filter.
I have a use case where I need to connect and immediately disconnect from a remote server. 

This is the error I am seeing.

[debug] event_add: event: 0x7fd99ac1e490 (fd 6), EV_READ    call 0x10811b8f0

[debug] event_callback_finalize_many_: 3 events finalizing

[debug] event_del: 0x7fd99ad00b00 (fd -1), callback 0x1081175c0

[debug] event_del: 0x7fd99ad00b80 (fd -1), callback 0x108117620

[debug] event_del: 0x7fd99ad00b00 (fd -1), callback 0x1081175c0

[debug] event_del: 0x7fd99ac1e490 (fd 6), callback 0x10811b8f0

[debug] event_del: 0x7fd99ad00b00 (fd -1), callback 0x108116c70

[debug] event_callback_finalize_many_: 3 events finalizing

[debug] event_del: 0x7fd99ac1e490 (fd 6), callback 0x10811b8f0

[debug] event_del: 0x7fd99ac1e510 (fd 6), callback 0x10811bb30

[debug] event_del: 0x7fd99ac1e490 (fd 6), callback 0x10811b8f0

[debug] event_base_free_: 1 events were still set in base

[err] event.c:840: Assertion TAILQ_EMPTY(&base->activequeues[i]) failed in event_base_free_Abort trap: 6


I attached a small test program demonstrating the problem. You will have to change the LIBEVENT_BASE_DIR variable in the included Makefile.

I am able to get around the problem by not freeing the underlying bufferevent or by using event_base_free_nofinalize but then we are leaking memory according to valgrind.

It is not clear to me that I am even setting up this stuff properly even though it is working well. Any insight would be greatly appreciated!

Thanks for your time!

Topher





Nate Rosenblum | 9 Sep 18:19 2014

deadlock in bufferevent_disable on auxiliary thread

All--

I filed https://github.com/nmathewson/Libevent/issues/105 to track a deadlock that I ran into. Details are there; I regret that I don't have resources at the moment to investigate solutions so I've just filed for reference.

Best,

--nate
Gaurav Rastogi | 7 Sep 08:15 2014
Picon

https://github.com/cppexecutor/gexecutor

Hi

A few years ago we had hit a problem of calling a synchronous (blocking) legacy API call in an application designed to be asynchronous and non-blocking. There wasn't a simple solution to this problem other than to do a custom implementation based on worker threads.

So, I created a new library C++ GExecutor which makes it easy to build any hybrid asynchronous and synchronous application without having to do a custom implementation with worker threads or multi-threading. I saw there were ready made solutions in Java and Python but nothing was available for C++ or C.

I am posting this so others can benefit if they are faced with synchronous operations within event loop or using libevent in multi-threaded environment. 

It currently supports both libevent and boost::asio based event loops. Having libevent was great help to us in rapidly developing high performance network application. Here is the link to the source:

cheers!
Gaurav

--
Azat Khuzhin | 4 Sep 15:04 2014
Picon

Re: Design struggle

On Thu, Sep 04, 2014 at 12:17:20PM +0200, B.R. wrote:
> Anyhow, that does not change the fact that I need a single handler for the
> network reading, and then dispatch the messages to handler, filling their
> individual buffer and manually activating their event to trigger them, does
> it?

As far as I understand you - yes.

Cheers,
Azat.

> ---
> *B. R.*
> ​
***********************************************************************
To unsubscribe, send an e-mail to majordomo <at> freehaven.net with
unsubscribe libevent-users    in the body.

Viallard Anthony | 2 Sep 10:33 2014

Abnormal delay on read

Hello there,

I have a problem with libevent (version 2.0.21).

I have 2 programs. One is sending requests (lets call it program A) to 
the other (program B) which process the request and send the response.

There are 2 kinds of request: one sent each 10 seconds (like a ping) and 
another one which is sent asynchronously when A has to.

All is working good at the beginning. But after a while, there is a 
delay between the request sent by A and the trigger of the read callback 
on B. All the request are shifted. During this delay, B proceed old ping 
requests... And this delay gradually increases.

I did a tcpdump capture on each side and I see there isn't a delay on 
the ethernet layer.

It's like there a mysterious queue somewhere...

However, I think I do the correct things in my read callback and I don't 
use watermarks.

Maybe, someone has already seen this kind of bad behavior ?

Here the code of my read callback (this function is generic for my 2 
programs):

----------------------------------------------

static void _lev_read_cb(struct bufferevent *bev, void *arg)
{
	struct talk_socket *sock = arg;
	struct evbuffer *evbuf_in;
	struct evbuffer_ptr it;
	size_t in_avail;

	if(sock->mode == talk_socket_mode_listener
	   && sock->status == talk_socket_status_idle)
	{
		_change_stage(sock, talk_socket_status_reading);
	}

	if(sock->status != talk_socket_status_reading)
	{
		log_err("sock %p: Invalid sock status: '%s' (mode=%s)",
			     sock, talk_socket_get_status_str(sock),
			     sock->mode == talk_socket_mode_listener ? "in" : "out");
		return;
	}

	/* Here, we have 2 cases:
	 *  1) we received an incomplete message, so we stay waiting
          *     for the remaining data ... ;
	 *  2) there is a complete and so, we need to proceed ;
	 */
	evbuf_in = bufferevent_get_input(bev);
	it = evbuffer_search(evbuf_in, "\0", 1, NULL);
	if(it.pos < 0)
	{
		log_warn("sock %p: message is incomplete."
			      " Waiting the remaining data...",
			      sock);
		return;
	}

	if(it.pos == 0)
	{
		log_err("sock %p: empty message !",
			     sock);
		evbuffer_drain(evbuf_in, 1); /*remove the \0 character*/
		goto cleanup;
	}

	if((size_t)it.pos + 1 > TALK_MSG_MAX_LEN)
	{
		log_err("sock %p: msg received is too big (%zu bytes)!",
			     sock, (size_t)it.pos + 1);
		evbuffer_drain(evbuf_in, (size_t)it.pos + 1);
		goto cleanup;
	}

	/* According to the mode, instantiate a new request
          * if we're receiving a message from nowhere.
	 */
	if(sock->mode == talk_socket_mode_listener)
	{
		sock->request = talk_request_new(NULL, NULL);
		if(sock->request == NULL)
		{
			log_err("talk_request_new() failed");
			return;
		}

		log_dbg5("sock %p: [req:#%u] receiving new request...",
			      sock, sock->request->id);
	}
	else
	{
		log_dbg5("sock %p: [req:#%u] receiving reply...",
			      sock, sock->request->id);
	}

	/* copy message (with the \0 character) to msg struct */
	evbuffer_remove(evbuf_in,
                         sock->request->in.data, (size_t)it.pos + 1);

	log_dbg4("sock %p: [req:#%u] receiving msg of %zu byte(s): %s",
		      sock, sock->request->id, (size_t)it.pos,
		      sock->request->in.data);

	/* call user callback */
	sock->reqev_cb(sock,
		       talk_socket_reqev_recv,
		       sock->request, sock->cb_userdata);

	if(sock->mode == talk_socket_mode_listener)
	{
		/* send the reply */
		_change_stage(sock, talk_socket_status_idle);

		/* some debug */
		log_dbg4("sock %p: [req:#%u] sending reply...",
			      sock, sock->request->id);

		/* write to the socket */
		if(talk_socket_write(sock,
					sock->request) != 0)
		{
			log_err("sock %p: [req:#%u]"
				     " talk_socket_write() failed",
				     sock, sock->request->id);
			talk_request_free(sock->request);
			sock->request = NULL;
		}
	}
	else
	{
		/* the user have free the request in callback.
		 * So here, we reset request pointer and change
                  * the status of the socket
		 */
		sock->request = NULL;
		_change_stage(sock, talk_socket_status_idle);
	}

cleanup:
	/* there is remaining data in evbuffer ?
	 */
	in_avail = evbuffer_get_length(evbuf_in);
	if(in_avail > 0)
	{
		if(sock->mode == talk_socket_mode_listener)
		{
			log_dbg4("sock %p: remaining %zu byte(s)"
                                  " of data",
				      sock, in_avail);
		}
		else
		{
			log_err("sock %p: remaining data after
                                  " proceeding a msg ! Discarding"
                                  " %zu byte(s) !",
				     sock, in_avail);
			evbuffer_drain(evbuf_in, in_avail);
		}
	}
}
----------------------------------------------

Moreover, after read callback is called, I don't have any remaining data 
in the input evbuffer (I don't see the log messages).

Writing this email, I'm wondering if the evbuffer_get_length() function 
works in all contexts ? I mean, I disable the read callback when the 
"socket" is writing for example.

I missed something ?

Anthony V.
***********************************************************************
To unsubscribe, send an e-mail to majordomo <at> freehaven.net with
unsubscribe libevent-users    in the body.

gerkenjohannes | 29 Aug 18:30 2014
Picon

Assert fail in evhttp_connection_fail_ with req=0x00 on error=EVREQ_HTTP_TIMEOUT at http.c:691

Hi,

when I add new evhttp requests to an running event_loop, I get "epoll ADD: Bad file descriptor" and later "SIGABRT".
The event_base is running in an seperate worker thread, the main thread is doing the evhttp_make_request.

Output from GDB:
http://paste.ubuntu.com/8176676/

Output from GDB with libevent debugging on:
http://paste.ubuntu.com/8176681/

I get the assert fail in the folowing 2 cases:

case 1:
1. add new requests to the running event_base

case 2:
1. call loop_brake from the main thread
2. wait for the loop to "brake" in the worker thread
3. put the worker thread to sleep
4. add new requests
5. wake up the worker thread
6. run the event_loop

Is this bug in libevent or my code?

Best regards,
***********************************************************************
To unsubscribe, send an e-mail to majordomo <at> freehaven.net with
unsubscribe libevent-users    in the body.

B.R. | 29 Aug 17:53 2014
Picon

Design struggle

I am trying to implement a modular filter plug-in system on top of libevent.

The main concept principles are:
1°) Filters are created cointaining information of connections they should be bound to (protocol, port), events that should trigger them and a callback pointer to link with the event
2°) Based on those filters, the necessary sockets are created and each socket is linked to a list of filters matching them
3°) For each filter, an event is created liking the callback to the socket file descriptor
4°) Each filter is then able to read information from the socket and possibly stack information to write that socket, registering a WRITE event on it

My concern here are concurrency (not really race condition since the app is single-threaded) :
I) If multiple filters ask to be triggered on READ event on the same socket, what will they see? Will they all be able to read the same message which triggered the event and not another one (ie another message received while processing the filter list)?

II) If multiple filters wanna write data to the socket, is it safe to have each filter having its separate buffer and triggering its own WRITE event on it?

Here is a use case summing up both previous inquiries:
Say a filter wrote data to a socket after parsing the content it read on it, and that the peer reacted to that answer, what will subsequent filters, for which the READ event has been triggered by the initial message, read?
a) Initial message?
b) Either initial message or answer (race, undecided)?
c) Nothing since the event has been canceled (not pending anymore), the subsequent filters will only receive a new event for READ on reception of the answer

I am thinking of using a dispatcher which would sequentially (and manually) trigger the event of each of the filters. However that implies not linking the filters event with the socket, thus forcing me to maintain a separate buffer for each of the filter (with memory and processing overhead that implies). Moreover, the problem reappears if another message is received on the socket while the dispatching loop is at work... and the sequential work makes the benefit of the event-based system disappear!

I do not know if the bufferevents would be useful to my case. Anyway, those are not an option, since part of the traffic I am handling is UDP datagrams.

I am new to the library. Please enlighten me if I have missed some key points in its design/handling.
---
B. R.
B.R. | 18 Aug 15:33 2014
Picon

Linking to library in other project

Hello,

I am a new user here :o)

I plan on using the libevent library for the very first time in a project.
I wonder about something related to cross-compiling for Windows and Linux:

I compiled libevent with MinGW+MSYS on Windows in order to link my project against the libevent.a (static linking).
What if I want to link my project with the same library for the Linux version? I do not see any libevent.lib. Shall I use the libevent.a again? Or should I compile libevent in Linux first then use its output library, which I guess would be libevent(.dll).lib?

​Thanks,​

---
B. R.
Erik Fears | 9 Aug 03:53 2014
Picon

evdns_cancel_request may not fully cancel

Hello,

I've run into an issue in my codebase where it appears evdns is calling 
a callback on a request that I've canceled.

This is an issue for me, because once I call evdns_cancel_request, I've 
also freed my own context associated with the request (i.e. the 
void* passed back by libevent to the callback).

If the result was always DNS_ERR_CANCEL on a cancelled request, 
this wouldn't be a problem, because I could abort. It seems that in some 
cases the result could be DNS_ERR_NONE if the callback was 
already pending


I believe this code may be to blame?

void
evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle)
        ...

EVDNS_LOCK(base);
if (handle->pending_cb) {
EVDNS_UNLOCK(base);
return;
}
   
        ...
}

Is this expected?

Thanks!
Erik


Gmane