Bill Vaughan | 25 Feb 15:25 2015
Picon

assert in event_del_internal()

Hi all,

We have been seeing a fairly hard to reproduce problem with crashes inside of libevent in our overnight scale tests.  We run 15,000 clients in an  ESX environment and have been getting one or two crashes per night. We are running libevent 2.0.21 on this test system. We have moved to 2.0.22 on our development branch.

The application is relatively large and complex and it is quite possible we have a memory trampler, but valgrind tests so far are clean and code inspection hasn't found anything.

We recently ran the overnight test with libevent debugging enabled (event_enable_debug_mode(), evthread_enable_lock_debuging()) and had the following assert in the libevent debug hash table:


[err] event_del_internal: noting a del on a non-setup event 0xb56248a0 (events: 0x0, fd: -1, flags: 0x80)
=== Command detached from window (Mon Feb 23 23:13:14 2015) ===
=== Command terminated with signal 6 (core file generated) (Mon Feb 23 23:13:14 2015) ===
 

Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
Core was generated by `./vtc_app -Script-Client29-333'.
Program terminated with signal 6, Aborted.
#0  0xb775e424 in __kernel_vsyscall ()
(gdb) where
#0  0xb775e424 in __kernel_vsyscall ()
#1  0xb747a1df in raise () from /lib/i386-linux-gnu/libc.so.6
#2  0xb747d825 in abort () from /lib/i386-linux-gnu/libc.so.6
#3  0x0814bc31 in event_exit (errcode=-559030611) at log.c:79
#4  0x0814bd53 in event_errx (eval=-559030611,
    fmt=0x82105b0 "%s: noting a del on a non-setup event %p (events: 0x%x, fd: %d, flags: 0x%x)") at log.c:136
#5  0x0813dc07 in event_del_internal (ev=<optimized out>) at event.c:2265
#6  event_process_active_single_queue (activeq=<optimized out>, base=<optimized out>) at event.c:1324
#7  event_process_active (base=<optimized out>) at event.c:1420
#8  event_base_loop (base=0xb6a09d58, flags=2) at event.c:1621
#9  0x08073960 in VtcCommMgr::ThreadLoop (this=0xacdcc008) at vtc_app/vtc_comm_mgr.cpp:844
#10 0xb772cd4c in start_thread () from /lib/i386-linux-gnu/libpthread.so.0
#11 0xb753ad3e in clone () from /lib/i386-linux-gnu/libc.so.6


So looks like an event fired that was not in the hash table, which should only happen if the event was freed, from what I can tell. This points to a clear application bug, however, there is a bit more to the store.

Examining the libevent hash table that tracks the events, we found this:

== 667 0xb5e248f0 ==
     {node = {hte_next = 0x0}, ptr = 0x0, added = 0}
global_debug_map.hth_table[666].node.hte_next
== 668 0xb5600858 ==
     {node = {hte_next = 0x0}, ptr = 0xb5600808, added = 1}
global_debug_map.hth_table[667].node.hte_next
== 669 0xb5624950 ==
     {node = {hte_next = 0x0}, ptr = 0xb5624900, added = 1}
global_debug_map.hth_table[668].node.hte_next
== 676 0x97a5390 ==
     {node = {hte_next = 0x0}, ptr = 0x97a50a8, added = 0}
global_debug_map.hth_table[669].node.hte_next
 

Bucket 667 has an entry, but the pointer to the event is 0.  The hash entry should be deleted (mm_free()) when the event is freed, and have a valid event pointer otherwise, so the event likely was not freed. All of the other entries in the hash look good. The event that is currently being processed in the backtrace, 0xb56248a0, maps to bucket 667 based on the hash algorithm:  ((0xb56248a0 >> 6) % 769) == 667, which is our bucket. This appears to be some sort of corruption if I am understanding the hash table logic correctly.

The event base was good and our application only calls event_free() and not any of the other APIs that could free an event from the hash (event_reinit() and a couple others).

I see in the 2.0.22 release notes that a race was fixed in event_active().  Do you think that could cause this? Our next step is to move to 2.0.22 on our test system to see if the problem still happens. However, this branch of code is very close to a release, so we are very cautious about changing things without a clear cause and effect.

We have had several engineers reviewing the application code and so far have not seen any invalid libevent usages, and as I said, valgrind is clean. Clearly we are doing something wrong in the application or have found some sort of edge case within the library. And libevent 2.0.21 has been very stable as I have used it on this project and others.

The application is complicated enough that I can't easily provide code snippets that are meaningful, and since we are not sure how to reproduce the problem, I don't have any test code that can reproduce it.

All of the clients are running under Ubuntu 12.04.

Has anyone else seen anything like this?

Thanks,
-Bill



Christian Stieber | 19 Feb 10:04 2015
Picon

Do paired buffer events work?

I've been trying to use them for a while now, without much success.

I seem to be able to put data into "my" side of the pair, and it appears
on the "remote" side -- but no callbacks are called on the remote end.

    Log("WebSocket %p received %u bytes",this,(unsigned
int)TheMessage->payload_len);
    if
(bufferevent_write(MyBufferEvent,TheMessage->payload,(size_t)TheMessage->payload_len)!=0)
    {
        /* throw ... */
    }
    else
    {
        bufferevent_flush(MyBufferEvent,EV_WRITE|EV_READ,BEV_NORMAL);

        Log("MyBufferEvent has output size
%d",(int)evbuffer_get_length(bufferevent_get_output(MyBufferEvent)));
        Log("RemoteBufferEvent %p has input size %d",(struct
bufferevent*)RemoteBufferEvent,(int)evbuffer_get_length(bufferevent_get_input(RemoteBufferEvent)));

        Log("RemoteBufferEvent has reading enabled:
%s",(bufferevent_get_enabled(RemoteBufferEvent) & EV_READ) ? "yes"
: "no");

This actually gives me the expected output, such as

[2015-02-19 08:08:54] WebSocket 0x7f8f080008c0 received 4 bytes
[2015-02-19 08:08:54] MyBufferEvent has output size 0
[2015-02-19 08:08:54] RemoteBufferEvent 0x7f8f08001370 has input size 4
[2015-02-19 08:08:54] RemoteBufferEvent has reading enabled: yes

but that's it -- the callback on the remote end simply isn't called.

I can send more data to the websocket thing and it's just added to the
output buffer of the "remote" end of the pair like it should, except that
it's never used since the callbacks are never invoked.

The same applies when I run flush with a BEV_FINISHED to signal an "EOF"
-- it's not happening on the remote end.

I'm just going to try calling those callbacks myself, probably with some
testing to detect when those callbacks start working so I know to update
the code then; not currently expecting too many problems with that. The
question is whether I'm still doing something wrong, somewhere, or whether
those callbacks are only meant for "real" sockets?

I was using "2.1.4-alpha" up until a couple of hours ago; updated to
"2.1.5-beta" and ran the thing again, but it didn't seem to change
anything

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

Marco Graziano | 11 Feb 06:06 2015

deadlock in callbacks

I am running into a deadlock with both libevent 2.0 and 2.1 that I cannot explain. One thread is executing a write callback and the other thread a read callback of a different bufferevent. Since they are both accessing the same data structure passed to the callbacks (arg=0x630c40), I am using a rwlock in the data structure. I did not expect though the evbuffer internal lock to interfere with the lock used to synchronize access to the data structure shared between the callbacks.

I am including the backtraces and the relevant portions of code. I would appreciate if someone can give me any suggestion on how to work around this.

Thanks,

-Marco G.

(gdb) t 1
[Switching to thread 1 (Thread 0x7ffff7fdd780 (LWP 12008))]
(gdb) bt
#0  __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
#1  0x00007ffff7770672 in _L_lock_953 () from /lib/x86_64-linux-gnu/libpthread.so.0
#2  0x00007ffff77704da in __GI___pthread_mutex_lock (mutex=0x620200) at ../nptl/pthread_mutex_lock.c:114
#3  0x00007ffff7b9686e in evbuffer_get_length (buffer=0x630930) at buffer.c:610
#4  0x000000000040494b in device_write_cb (bev=0x123f640, arg=0x630c40) at cometa.c:667
#5  0x00007ffff7ba2139 in bufferevent_trigger_nolock_ (options=0, iotype=4, bufev=0x123f640) at bufferevent-internal.h:369
#6  bufferevent_writecb (fd=<optimized out>, event=<optimized out>, arg=0x123f640) at bufferevent_sock.c:297
#7  0x00007ffff7ba7a19 in event_persist_closure (ev=<optimized out>, base=0x6218d0) at event.c:1531
#8  event_process_active_single_queue (base=base <at> entry=0x6218d0, activeq=0x621d20, max_to_process=max_to_process <at> entry=2147483647, 
    endtime=endtime <at> entry=0x0) at event.c:1590
#9  0x00007ffff7ba82cf in event_process_active (base=0x6218d0) at event.c:1689
#10 event_base_loop (base=0x6218d0, flags=0) at event.c:1912
#11 0x000000000040a700 in main () at cometa.c:1571


bufferevent 0x123f640 write callback:
665    pthread_rwlock_wrlock(&device->lock);
666    if ((device->pending && device->state == WAITING_STATE) || device->ws_pending) {
667     int l = evbuffer_get_length(device_bev);   
668     pthread_rwlock_unlock(&device->lock);
669     output = bufferevent_get_output(device->pending->bufev);
670 if (evbuffer_get_length(output) == 0) {
671 /* free and close the connection */
672 pthread_rwlock_wrlock(&device->lock);
673     free_http_connection(device->pending);
674     device->pending = NULL;
675     device->state = IDLE_STATE;
676   device->chunk_length = 0;
677     device->ntoread = -1;
678
679     evbuffer_drain (device_bev, l);
680   sem_post(&device->active);
681   pthread_rwlock_unlock(&device->lock);
682     }
683    } else {
684     pthread_rwlock_unlock(&device->lock);
685    }


(gdb) t 3
[Switching to thread 3 (Thread 0x7ffff532f700 (LWP 12013))]
(gdb) bt
#0  pthread_rwlock_wrlock () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S:85
#1  0x0000000000404667 in device_read_cb (bev=0x630730, arg=0x630c40) at cometa.c:604
#2  0x00007ffff7ba2324 in bufferevent_trigger_nolock_ (options=0, iotype=2, bufev=0x630730) at bufferevent-internal.h:366
#3  bufferevent_readcb (fd=34, event=<optimized out>, arg=0x630730) at bufferevent_sock.c:187
#4  0x00007ffff7ba7a19 in event_persist_closure (ev=<optimized out>, base=0x7fffe8000900) at event.c:1531
#5  event_process_active_single_queue (base=base <at> entry=0x7fffe8000900, activeq=0x7fffe8000d50, 
    max_to_process=max_to_process <at> entry=2147483647, endtime=endtime <at> entry=0x0) at event.c:1590
#6  0x00007ffff7ba82cf in event_process_active (base=0x7fffe8000900) at event.c:1689
#7  event_base_loop (base=0x7fffe8000900, flags=0) at event.c:1912
#8  0x000000000040a1ff in device_loop (arg=0x0) at cometa.c:1437
#9  0x00007ffff776e182 in start_thread (arg=0x7ffff532f700) at pthread_create.c:312
#10 0x00007ffff689700d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

bufferevent 0x630730 read call back:
604 pthread_rwlock_wrlock(&device->lock); 
605    if (device->state != WAITING_STATE) {
606    
607   device->chunk_length = 0;
608     device->ntoread = -1;
609     /* in case of state == WAITING_STATE the counters reset is done in the write callback after sending the response */
610    }
611 pthread_rwlock_unlock(&device->lock);

Marco Graziano | 10 Feb 17:32 2015

undefined reference to event_base_add_virtual in libevent 2.1

Getting a linker error using libevent 2.1:

marcog <at> marcog-VirtualBox:~/Cometa/cometa-mt/server$ make
cc -Wall -g -I./include -L/usr/local/lib -levent -o cometa cometa.o request.o http_parser.o config.o rsyslog.o response.o routes.o api.o info.o webhooks.o websockets.o -l:libevent-2.1.so.5  -l:libevent_pthreads-2.1.so.5 -lpthread -lcrypto -lm -ldl -lwebsock -lconfig -lssl -lworkqueue -lbeanstalk 
/usr/bin/ld: cometa.o: undefined reference to symbol 'event_base_add_virtual'
/usr/local/lib/libevent-2.0.so.5: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
make: *** [cometa] Error 1

While everything is fine with libevent 2.0:

marcog <at> marcog-VirtualBox:~/Cometa/cometa-mt/server$ make
cc -Wall -g -I./include -L/usr/local/lib -levent -o cometa cometa.o request.o http_parser.o config.o rsyslog.o response.o routes.o api.o info.o webhooks.o websockets.o -l:libevent-2.0.so.5  -l:libevent_pthreads-2.0.so.5 -lpthread -lcrypto -lm -ldl -lwebsock -lconfig -lssl -lworkqueue -lbeanstalk 

The symbol is defined in both libraries:

 

Marco Graziano | Founder & CEO | Visible Energy, Inc. | 530 Lytton Avenue, 2nd Floor, Palo Alto, CA 94301
Tel: (650)353-7812  | Cell: (650)644-8867
Before you print this email or/ attachments, please consider the negative environmental impacts associated with printing. 

Praveen Kariyanahalli | 3 Feb 22:39 2015

Memory (heap meta-data) corruption while using buffervent_openssl apis


Client (bufferevent + openssl) crash only under load situation.  Valgrind points to this backtrace. Any help is greatly appreciated ? Please let us know if you need any more information.

Thanks
-Praveen

Version: 2.0.22

==695== Invalid write of size 8
==695==    at 0x52CF66B: evmap_io_add (evmap.c:328)
==695==    by 0x52BC638: event_add_internal (event.c:2073)
==695==    by 0x52BC150: event_add (event.c:1966)
==695==    by 0x5504678: bufferevent_openssl_new_impl (bufferevent_openssl.c:1368)
==695==    by 0x550482B: bufferevent_openssl_socket_new (bufferevent_openssl.c:1440)
==695==    by 0x43211A: tls_connect_timer_cb (my_client_peer.c:528)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 232 bytes inside a block of size 608 free'd
==695==    at 0x4A0739B: free (vg_replace_malloc.c:473)
==695==    by 0x48B3EB: vip_guard_mem_free (vip_gaurd_mem.c:157)
==695==    by 0x52BE3F7: event_mm_free_ (event.c:2696)
==695==    by 0x52C878B: _bufferevent_decref_and_unlock (bufferevent.c:650)
==695==    by 0x52C8874: bufferevent_free (bufferevent.c:681)
==695==    by 0x435747: my_client_peer_delete (my_client_peer.c:1257)
==695==    by 0x430EE8: my_client_peer_timer_exp_cb (my_client_peer.c:267)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==
==695== Invalid write of size 8
==695==    at 0x52CF8DD: evmap_io_del (evmap.c:384)
==695==    by 0x52BCE7B: event_del_internal (event.c:2251)
==695==    by 0x52BCBD7: event_del (event.c:2188)
==695==    by 0x55034A0: consider_writing (bufferevent_openssl.c:881)
==695==    by 0x5503D41: be_openssl_outbuf_cb (bufferevent_openssl.c:1119)
==695==    by 0x52C0B58: evbuffer_run_callbacks (buffer.c:486)
==695==    by 0x52C0C51: evbuffer_invoke_callbacks (buffer.c:508)
==695==    by 0x52C61AD: evbuffer_add_reference (buffer.c:2718)
==695==    by 0x41EF6E: my_client_pkt_send (my_client_msg.c:75)
==695==    by 0x445807: my_client_tunn_event_cb (my_client_tun_intf.c:157)
==695==    by 0x52BA162: event_persist_closure (event.c:1301)
==695==    by 0x52BA271: event_process_active_single_queue (event.c:1345)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 232 bytes inside a block of size 608 free'd
==695==    at 0x4A0739B: free (vg_replace_malloc.c:473)
==695==    by 0x48B3EB: vip_guard_mem_free (vip_gaurd_mem.c:157)
==695==    by 0x52BE3F7: event_mm_free_ (event.c:2696)
==695==    by 0x52C878B: _bufferevent_decref_and_unlock (bufferevent.c:650)
==695==    by 0x52C8874: bufferevent_free (bufferevent.c:681)
==695==    by 0x435747: my_client_peer_delete (my_client_peer.c:1257)
==695==    by 0x430EE8: my_client_peer_timer_exp_cb (my_client_peer.c:267)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==
==695== Invalid write of size 8
==695==    at 0x52CF8DD: evmap_io_del (evmap.c:384)
==695==    by 0x52BCE7B: event_del_internal (event.c:2251)
==695==    by 0x52BCBD7: event_del (event.c:2188)
==695==    by 0x550260C: stop_reading (bufferevent_openssl.c:422)
==695==    by 0x55028CE: conn_closed (bufferevent_openssl.c:528)
==695==    by 0x5502F56: do_write (bufferevent_openssl.c:694)
==695==    by 0x55033ED: consider_writing (bufferevent_openssl.c:874)
==695==    by 0x5503D41: be_openssl_outbuf_cb (bufferevent_openssl.c:1119)
==695==    by 0x52C0B58: evbuffer_run_callbacks (buffer.c:486)
==695==    by 0x52C0C51: evbuffer_invoke_callbacks (buffer.c:508)
==695==    by 0x52C61AD: evbuffer_add_reference (buffer.c:2718)
==695==    by 0x41EF6E: my_client_pkt_send (my_client_msg.c:75)
==695==    by 0x445807: my_client_tunn_event_cb (my_client_tun_intf.c:157)
==695==    by 0x52BA162: event_persist_closure (event.c:1301)
==695==    by 0x52BA271: event_process_active_single_queue (event.c:1345)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 232 bytes inside a block of size 608 free'd
==695==    at 0x4A0739B: free (vg_replace_malloc.c:473)
==695==    by 0x48B3EB: vip_guard_mem_free (vip_gaurd_mem.c:157)
==695==    by 0x52BE3F7: event_mm_free_ (event.c:2696)
==695==    by 0x52C878B: _bufferevent_decref_and_unlock (bufferevent.c:650)
==695==    by 0x52C8874: bufferevent_free (bufferevent.c:681)
==695==    by 0x435747: my_client_peer_delete (my_client_peer.c:1257)
==695==    by 0x430EE8: my_client_peer_timer_exp_cb (my_client_peer.c:267)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==
==695== Invalid write of size 8
==695==    at 0x52CF8DD: evmap_io_del (evmap.c:384)
==695==    by 0x52BCE7B: event_del_internal (event.c:2251)
==695==    by 0x52BCBD7: event_del (event.c:2188)
==695==    by 0x5502659: stop_writing (bufferevent_openssl.c:435)
==695==    by 0x55028DA: conn_closed (bufferevent_openssl.c:529)
==695==    by 0x5502F56: do_write (bufferevent_openssl.c:694)
==695==    by 0x55033ED: consider_writing (bufferevent_openssl.c:874)
==695==    by 0x5503D41: be_openssl_outbuf_cb (bufferevent_openssl.c:1119)
==695==    by 0x52C0B58: evbuffer_run_callbacks (buffer.c:486)
==695==    by 0x52C0C51: evbuffer_invoke_callbacks (buffer.c:508)
==695==    by 0x52C61AD: evbuffer_add_reference (buffer.c:2718)
==695==    by 0x41EF6E: my_client_pkt_send (my_client_msg.c:75)
==695==    by 0x445807: my_client_tunn_event_cb (my_client_tun_intf.c:157)
==695==    by 0x52BA162: event_persist_closure (event.c:1301)
==695==    by 0x52BA271: event_process_active_single_queue (event.c:1345)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 232 bytes inside a block of size 608 free'd
==695==    at 0x4A0739B: free (vg_replace_malloc.c:473)
==695==    by 0x48B3EB: vip_guard_mem_free (vip_gaurd_mem.c:157)
==695==    by 0x52BE3F7: event_mm_free_ (event.c:2696)
==695==    by 0x52C878B: _bufferevent_decref_and_unlock (bufferevent.c:650)
==695==    by 0x52C8874: bufferevent_free (bufferevent.c:681)
==695==    by 0x435747: my_client_peer_delete (my_client_peer.c:1257)
==695==    by 0x430EE8: my_client_peer_timer_exp_cb (my_client_peer.c:267)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==
==695== Invalid write of size 8
==695==    at 0x52CF8DD: evmap_io_del (evmap.c:384)
==695==    by 0x52BCE7B: event_del_internal (event.c:2251)
==695==    by 0x52BCBD7: event_del (event.c:2188)
==695==    by 0x5503FB5: be_openssl_destruct (bufferevent_openssl.c:1183)
==695==    by 0x52C85F5: _bufferevent_decref_and_unlock (bufferevent.c:622)
==695==    by 0x52C8874: bufferevent_free (bufferevent.c:681)
==695==    by 0x435747: my_client_peer_delete (my_client_peer.c:1257)
==695==    by 0x430EE8: my_client_peer_timer_exp_cb (my_client_peer.c:267)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 232 bytes inside a block of size 560 free'd
==695==    at 0x4A0739B: free (vg_replace_malloc.c:473)
==695==    by 0x48B3EB: vip_guard_mem_free (vip_gaurd_mem.c:157)
==695==    by 0x41EE2F: my_client_pktbuf_free (my_client_msg.c:54)
==695==    by 0x52BFFEC: evbuffer_chain_free (buffer.c:198)
==695==    by 0x52C251D: evbuffer_drain (buffer.c:972)
==695==    by 0x5502FA2: do_write (bufferevent_openssl.c:703)
==695==    by 0x55033ED: consider_writing (bufferevent_openssl.c:874)
==695==    by 0x5503D41: be_openssl_outbuf_cb (bufferevent_openssl.c:1119)
==695==    by 0x52C0B58: evbuffer_run_callbacks (buffer.c:486)
==695==    by 0x52C0C51: evbuffer_invoke_callbacks (buffer.c:508)
==695==    by 0x52C61AD: evbuffer_add_reference (buffer.c:2718)
==695==    by 0x41EF6E: my_client_pkt_send (my_client_msg.c:75)
==695==    by 0x426213: my_client_generic_send_message (my_client_msg.c:1708)
==695==    by 0x4297B9: my_client_peer_send_hello (my_client_msg.c:2181)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==
==695== Invalid write of size 8
==695==    at 0x52CF66B: evmap_io_add (evmap.c:328)
==695==    by 0x52BC638: event_add_internal (event.c:2073)
==695==    by 0x52BC150: event_add (event.c:1966)
==695==    by 0x52E695D: _evdns_nameserver_add_impl (evdns.c:2496)
==695==    by 0x52E6D7C: evdns_base_nameserver_ip_add (evdns.c:2592)
==695==    by 0x52E9B9B: resolv_conf_parse_line (evdns.c:3471)
==695==    by 0x52E9ECE: evdns_base_resolv_conf_parse_impl (evdns.c:3572)
==695==    by 0x52E9D60: evdns_base_resolv_conf_parse (evdns.c:3508)
==695==    by 0x52EA1A7: evdns_base_new (evdns.c:3881)
==695==    by 0x41AF33: my_client_connect_to_peer_my_clients (my_client.c:4978)
==695==    by 0x430FC6: my_client_peer_timer_exp_cb (my_client_peer.c:285)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 1,480 bytes inside an unallocated block of size 2,960 in arena "client"
==695==
==695== Invalid write of size 8
==695==    at 0x52CF8DD: evmap_io_del (evmap.c:384)
==695==    by 0x52BCE7B: event_del_internal (event.c:2251)
==695==    by 0x52BCBD7: event_del (event.c:2188)
==695==    by 0x52EA318: evdns_nameserver_free (evdns.c:3930)
==695==    by 0x52EA4EB: evdns_base_free_and_unlock (evdns.c:3965)
==695==    by 0x52EA6DD: evdns_base_free (evdns.c:4001)
==695==    by 0x41A5AE: my_client_dns_getaddrinfo_cb (my_client.c:4778)
==695==    by 0x52EB9E9: evdns_getaddrinfo (evdns.c:4563)
==695==    by 0x41B02E: my_client_connect_to_peer_my_clients (my_client.c:5000)
==695==    by 0x430FC6: my_client_peer_timer_exp_cb (my_client_peer.c:285)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 1,480 bytes inside an unallocated block of size 2,960 in arena "client"
==695==
==695== Invalid write of size 8
==695==    at 0x52CF66B: evmap_io_add (evmap.c:328)
==695==    by 0x52BC638: event_add_internal (event.c:2073)
==695==    by 0x52BC150: event_add (event.c:1966)
==695==    by 0x431580: ssl_connect_timer_cb (my_client_peer.c:371)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 1,480 bytes inside an unallocated block of size 2,960 in arena "client"
==695==
==695== Invalid write of size 8
==695==    at 0x52CF8DD: evmap_io_del (evmap.c:384)
==695==    by 0x52BCE7B: event_del_internal (event.c:2251)
==695==    by 0x52BCBD7: event_del (event.c:2188)
==695==    by 0x52BB484: event_free (event.c:1809)
==695==    by 0x435B36: my_client_peer_delete (my_client_peer.c:1323)
==695==    by 0x430EE8: my_client_peer_timer_exp_cb (my_client_peer.c:267)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==    by 0x41E5BA: main (my_client.c:6024)
==695==  Address 0x86ff848 is 8 bytes inside a block of size 160 free'd
==695==    at 0x4A0739B: free (vg_replace_malloc.c:473)
==695==    by 0x48B3EB: vip_guard_mem_free (vip_gaurd_mem.c:157)
==695==    by 0x5BFD5F9: CRYPTO_free (mem.c:401)
==695==    by 0x5CA9915: EVP_MD_CTX_cleanup (digest.c:390)
==695==    by 0x5CA532E: ssleay_rand_bytes (md_rand.c:525)
==695==    by 0x5CA53DB: ssleay_rand_pseudo_bytes (md_rand.c:548)
==695==    by 0x5CA5C67: RAND_pseudo_bytes (rand_lib.c:173)
==695==    by 0x594394A: ssl_fill_hello_random (s23_clnt.c:294)
==695==    by 0x5951112: dtls1_client_hello (d1_clnt.c:801)
==695==    by 0x59505CB: dtls1_connect (d1_clnt.c:302)
==695==    by 0x595C8E0: SSL_connect (ssl_lib.c:943)
==695==    by 0x441DBC: create_ssl_conn_to_peer (my_client_misc.c:2134)
==695==    by 0x4346AB: my_client_peer_create (my_client_peer.c:1018)
==695==    by 0x41B1BB: my_client_connect_to_peer_my_clients (my_client.c:5022)
==695==    by 0x41ABF9: my_client_dns_getaddrinfo_cb (my_client.c:4886)
==695==    by 0x52EB9E9: evdns_getaddrinfo (evdns.c:4563)
==695==    by 0x41B02E: my_client_connect_to_peer_my_clients (my_client.c:5000)
==695==    by 0x430FC6: my_client_peer_timer_exp_cb (my_client_peer.c:285)
==695==    by 0x488AC6: timer_exec_pri (timer.c:612)
==695==    by 0x4885A1: timer_exec (timer.c:504)
==695==    by 0x41A165: my_client_base_timer_cb (my_client.c:4671)
==695==    by 0x52BA2CC: event_process_active_single_queue (event.c:1350)
==695==    by 0x52BA540: event_process_active (event.c:1420)
==695==    by 0x52BABA7: event_base_loop (event.c:1621)
==695==    by 0x41C5D9: my_client_main (my_client.c:5437)
==695==

valgrind: /jenkins/master/builder/x86_64/tmp/work/x86_64-poky-linux/valgrind/3.10.0-r15/valgrind-3.10.0/coregrind/m_mallocfree.c:304
(get_bszB_as_is): Assertion 'bszB_lo == bszB_hi' failed.
valgrind: Heap block lo/hi size mismatch: lo = 224, hi = 0.
Nate Rosenblum | 27 Jan 22:29 2015

curl_mutli and edge-triggered events

Profiling an application that uses the `curl_multi_socket_action` interface, I noticed that the writeable-socket callback for my event framework (libevent in this case) was being invoked many times when issuing HTTP GET requests. I quickly determined that this stems from configuring libevent for level-triggered & persistent socket events; libcurl registers for INOUT mode while sending the request and libevent will repeatedly raise writeable socket events until write registration is removed with another socket callback with `CURL_POLL_IN` (when waiting for the response). 

One wait to avoid these callbacks would be to set my events to be edge-triggered. I haven't read the multi implementation in sufficient detail to know if this is safe, however. If the underlying socket write returns EAGAIN while writing the the HTTP GET request, will libcurl invoke the socket callback to indicate its interest in writeable-socket notifications? Cursory reading suggests that it will not; it looks to me like determination of when to invoke the callback is based on the phase of the request in `singlesocket()`, and that the `Curl_sh_entry.action` field is not updated outside of that method.

Perhaps somebody with more familiarity can clarify or point out where I've gone wrong? For many concurrent transfers I am burning considerable CPU time servicing useless writeable-socket events and would love to avoid them.

Best,

--nate
Steffen Christgau | 24 Jan 17:33 2015
Picon

requests over HTTPS after server-side close

Hi everybody,

based on code of the https-client sample I use libevent for doing
HTTP(S) requests in one of my applications. It receives data from
another process (via socket using libevent as well), transforms the
data, and issues HTTP requests based on the transformation result.
Between multiple data receptions from the external process there's some
random delay. In case the delay is long enough, the HTTP connection
established by libevent is closed by the server. When using HTTP
libevent automatically reconnects to the server as soon a new request
has been issued. So, everything is fine.

However, when HTTPS is used, the reconnect seems not work and no request
is performed after the server-side disconnect. I was able to reproduce
this behavior with a modified (although somewhat ugly) version of the
https-client example. You can find the source code in the attachment
(don't know if attachments are welcome in this mailing list). The
timeout in http_request_done simulates reception of data from the
external application which causes a new HTTP request to be triggered.
The timeout value should be chosen to let the callback be invoked after
the server closed the connection. You can try it with example.com and a
timeout value of 55 sec. For HTTP you will get a infinite loop of
requests. For HTTPS only one request is performed, the connection
closes, the timer callback is invoked and the application terminates.

I wonder which steps are required to get the code working with HTTPS as
it does with HTTP. From an application programmers view, I would expect
that there should be no difference, except for the bev creation (as in
the example). Do you have any suggestions? I'm using libevent 2.1.5-beta
(although I observed this in 2.1.3 and 2.1.4 as well) with OpenSSL
1.0.1k on Linux (gcc 4.8.3, glibc 2.19).

Kind regards,

Steffen
/*
  This is an example of how to hook up evhttp with bufferevent_ssl

  It just GETs an https URL given on the command-line and prints the response
  body to stdout.

  Actually, it also accepts plain http URLs to make it easy to compare http vs
  https code paths.

  Loosely based on le-proxy.c.
 */

// Get rid of OSX 10.7 and greater deprecation warnings.
#if defined(__APPLE__) && defined(__clang__)
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>

#define snprintf _snprintf
#define strcasecmp _stricmp
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif

#include <event2/bufferevent_ssl.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/http.h>

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>

#include "openssl_hostname_validation.h"

static struct event_base *base;
static int ignore_cert = 0;
struct bufferevent *bev;
static const char* host;
static char* data_file;
static struct evhttp_connection *evcon;
static char uri[256];

static void perform_http_request(void);

static void close_cb(struct evhttp_connection *con, void *arg)
{
	printf("--- connection closed ---\n");
}

static void timer_cb(evutil_socket_t fd, short what, void *arg)
{
	printf("timer expired, issueing next request\n");
	perform_http_request();
}

static void
http_request_done(struct evhttp_request *req, void *ctx)
{
	char buffer[256];
	int nread;

	if (req == NULL) {
		/* If req is NULL, it means an error occurred, but
		 * sadly we are mostly left guessing what the error
		 * might have been.  We'll do our best... */
		struct bufferevent *bev = (struct bufferevent *) ctx;
		unsigned long oslerr;
		int printed_err = 0;
		int errcode = EVUTIL_SOCKET_ERROR();
		fprintf(stderr, "some request failed - no idea which one though!\n");
		/* Print out the OpenSSL error queue that libevent
		 * squirreled away for us, if any. */
		while ((oslerr = bufferevent_get_openssl_error(bev))) {
			ERR_error_string_n(oslerr, buffer, sizeof(buffer));
			fprintf(stderr, "%s\n", buffer);
			printed_err = 1;
		}
		/* If the OpenSSL error queue was empty, maybe it was a
		 * socket error; let's try printing that. */
		if (! printed_err)
			fprintf(stderr, "socket error = %s (%d)\n",
				evutil_socket_error_to_string(errcode),
				errcode);
		return;
	}

	fprintf(stderr, "Response line: %d %s\n",
	    evhttp_request_get_response_code(req),
	    evhttp_request_get_response_code_line(req));

	while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req),
		    buffer, sizeof(buffer)))
	       > 0) {
		/* These are just arbitrary chunks of 256 bytes.
		 * They are not lines, so we can't treat them as such. */
		fwrite(buffer, nread, 1, stdout);
	}

	{
		struct timeval tv = { 55, 0 };
		evtimer_add(evtimer_new(base, timer_cb, NULL), &tv);
	}

}

static void
syntax(void)
{
	fputs("Syntax:\n", stderr);
	fputs("   https-client -url <https-url> [-data data-file.bin] [-ignore-cert] [-retries num]\n", stderr);
	fputs("Example:\n", stderr);
	fputs("   https-client -url https://ip.appspot.com/\n", stderr);

	exit(1);
}

static void
die(const char *msg)
{
	fputs(msg, stderr);
	exit(1);
}

static void
die_openssl(const char *func)
{
	fprintf (stderr, "%s failed:\n", func);

	/* This is the OpenSSL function that prints the contents of the
	 * error stack to the specified file handle. */
	ERR_print_errors_fp (stderr);

	exit(1);
}

static void perform_http_request(void)
{
	int r;

	struct evhttp_request *req;
	struct evkeyvalq *output_headers;
	struct evbuffer * output_buffer;

	// Fire off the request
	req = evhttp_request_new(http_request_done, bev);
	if (req == NULL) {
		fprintf(stderr, "evhttp_request_new() failed\n");
		return;
	}

	output_headers = evhttp_request_get_output_headers(req);
	evhttp_add_header(output_headers, "Host", host);
//	evhttp_add_header(output_headers, "Connection", "close");

	if (data_file) {
		/* NOTE: In production code, you'd probably want to use
		 * evbuffer_add_file() or evbuffer_add_file_segment(), to
		 * avoid needless copying. */
		FILE * f = fopen(data_file, "rb");
		char buf[1024];
		size_t s;
		size_t bytes = 0;

		if (!f) {
			syntax();
		}

		output_buffer = evhttp_request_get_output_buffer(req);
		while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
			evbuffer_add(output_buffer, buf, s);
			bytes += s;
		}
		evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
		evhttp_add_header(output_headers, "Content-Length", buf);
		fclose(f);
	}

	r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
	if (r != 0) {
		fprintf(stderr, "evhttp_make_request() failed\n");
		return;
	}
}

/* See http://archives.seul.org/libevent/users/Jan-2013/msg00039.html */
static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
{
	char cert_str[256];
	const char *host = (const char *) arg;
	const char *res_str = "X509_verify_cert failed";
	HostnameValidationResult res = Error;

	/* This is the function that OpenSSL would call if we hadn't called
	 * SSL_CTX_set_cert_verify_callback().  Therefore, we are "wrapping"
	 * the default functionality, rather than replacing it. */
	int ok_so_far = 0;

	X509 *server_cert = NULL;

	if (ignore_cert) {
		return 1;
	}

	ok_so_far = X509_verify_cert(x509_ctx);

	server_cert = X509_STORE_CTX_get_current_cert(x509_ctx);

	if (ok_so_far) {
		res = validate_hostname(host, server_cert);

		switch (res) {
		case MatchFound:
			res_str = "MatchFound";
			break;
		case MatchNotFound:
			res_str = "MatchNotFound";
			break;
		case NoSANPresent:
			res_str = "NoSANPresent";
			break;
		case MalformedCertificate:
			res_str = "MalformedCertificate";
			break;
		case Error:
			res_str = "Error";
			break;
		default:
			res_str = "WTF!";
			break;
		}
	}

	X509_NAME_oneline(X509_get_subject_name (server_cert),
			  cert_str, sizeof (cert_str));

	if (res == MatchFound) {
		printf("https server '%s' has this certificate, "
		       "which looks good to me:\n%s\n",
		       host, cert_str);
		return 1;
	} else {
		printf("Got '%s' for hostname '%s' and certificate:\n%s\n",
		       res_str, host, cert_str);
		return 0;
	}
}

int
main(int argc, char **argv)
{
	int r;

	struct evhttp_uri *http_uri;
	const char *url = NULL;
	const char *scheme, *path, *query;
	int port;
	int retries = 0;

	SSL_CTX *ssl_ctx;
	SSL *ssl;

	int i;

	for (i = 1; i < argc; i++) {
		if (!strcmp("-url", argv[i])) {
			if (i < argc - 1) {
				url = argv[i + 1];
			} else {
				syntax();
			}
		} else if (!strcmp("-ignore-cert", argv[i])) {
			ignore_cert = 1;
		} else if (!strcmp("-data", argv[i])) {
			if (i < argc - 1) {
				data_file = argv[i + 1];
			} else {
				syntax();
			}
		} else if (!strcmp("-retries", argv[i])) {
			if (i < argc - 1) {
				retries = atoi(argv[i + 1]);
			} else {
				syntax();
			}
		} else if (!strcmp("-help", argv[i])) {
			syntax();
		}
	}

	if (!url) {
		syntax();
	}

#ifdef _WIN32
	{
		WORD wVersionRequested;
		WSADATA wsaData;
		int err;

		wVersionRequested = MAKEWORD(2, 2);

		err = WSAStartup(wVersionRequested, &wsaData);
		if (err != 0) {
			printf("WSAStartup failed with error: %d\n", err);
			return 1;
		}
	}
#endif // _WIN32

	http_uri = evhttp_uri_parse(url);
	if (http_uri == NULL) {
		die("malformed url");
	}

	scheme = evhttp_uri_get_scheme(http_uri);
	if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
	                       strcasecmp(scheme, "http") != 0)) {
		die("url must be http or https");
	}

	host = evhttp_uri_get_host(http_uri);
	if (host == NULL) {
		die("url must have a host");
	}

	port = evhttp_uri_get_port(http_uri);
	if (port == -1) {
		port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
	}

	path = evhttp_uri_get_path(http_uri);
	if (path == NULL) {
		path = "/";
	}

	query = evhttp_uri_get_query(http_uri);
	if (query == NULL) {
		snprintf(uri, sizeof(uri) - 1, "%s", path);
	} else {
		snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
	}
	uri[sizeof(uri) - 1] = '\0';

	// Initialize OpenSSL
	SSL_library_init();
	ERR_load_crypto_strings();
	SSL_load_error_strings();
	OpenSSL_add_all_algorithms();

	/* This isn't strictly necessary... OpenSSL performs RAND_poll
	 * automatically on first use of random number generator. */
	r = RAND_poll();
	if (r == 0) {
		die_openssl("RAND_poll");
	}

	/* Create a new OpenSSL context */
	ssl_ctx = SSL_CTX_new(SSLv23_method());
	if (!ssl_ctx)
		die_openssl("SSL_CTX_new");

	#ifndef _WIN32
	/* TODO: Add certificate loading on Windows as well */

	/* Attempt to use the system's trusted root certificates.
	 * (This path is only valid for Debian-based systems.) */
	if (1 != SSL_CTX_load_verify_locations(ssl_ctx,
					       "/etc/ssl/certs/ca-certificates.crt",
					       NULL))
		die_openssl("SSL_CTX_load_verify_locations");
	/* Ask OpenSSL to verify the server certificate.  Note that this
	 * does NOT include verifying that the hostname is correct.
	 * So, by itself, this means anyone with any legitimate
	 * CA-issued certificate for any website, can impersonate any
	 * other website in the world.  This is not good.  See "The
	 * Most Dangerous Code in the World" article at
	 * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
	 */
	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
	/* This is how we solve the problem mentioned in the previous
	 * comment.  We "wrap" OpenSSL's validation routine in our
	 * own routine, which also validates the hostname by calling
	 * the code provided by iSECPartners.  Note that even though
	 * the "Everything You've Always Wanted to Know About
	 * Certificate Validation With OpenSSL (But Were Afraid to
	 * Ask)" paper from iSECPartners says very explicitly not to
	 * call SSL_CTX_set_cert_verify_callback (at the bottom of
	 * page 2), what we're doing here is safe because our
	 * cert_verify_callback() calls X509_verify_cert(), which is
	 * OpenSSL's built-in routine which would have been called if
	 * we hadn't set the callback.  Therefore, we're just
	 * "wrapping" OpenSSL's routine, not replacing it. */
	SSL_CTX_set_cert_verify_callback (ssl_ctx, cert_verify_callback,
					  (void *) host);
	#endif // not _WIN32

	// Create event base
	base = event_base_new();
	if (!base) {
		perror("event_base_new()");
		return 1;
	}

	// Create OpenSSL bufferevent and stack evhttp on top of it
	ssl = SSL_new(ssl_ctx);
	if (ssl == NULL) {
		die_openssl("SSL_new()");
	}

	#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
	// Set hostname for SNI extension
	SSL_set_tlsext_host_name(ssl, host);
	#endif

	if (strcasecmp(scheme, "http") == 0) {
		bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
	} else {
		bev = bufferevent_openssl_socket_new(base, -1, ssl,
			BUFFEREVENT_SSL_CONNECTING,
			BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
	}

	if (bev == NULL) {
		fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
		return 1;
	}

	bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);

	// For simplicity, we let DNS resolution block. Everything else should be
	// asynchronous though.
	evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
		host, port);
	if (evcon == NULL) {
		fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
		return 1;
	}

	if (retries > 0) {
		evhttp_connection_set_retries(evcon, retries);
	}

	evhttp_connection_set_closecb(evcon, close_cb, NULL);

	perform_http_request();
	event_base_dispatch(base);

	evhttp_connection_free(evcon);
	event_base_free(base);

#ifdef _WIN32
	WSACleanup();
#endif

	return 0;
}
Andre | 23 Jan 03:35 2015
Picon

Windows and bufferevent_socket_connect

Hello

I have a project that works perfectly in Ubuntu. But I want to port it 
to Windows. So I compiled it with MinGW for Windows and no errors 
occurred while compiling.

Then I tried to run it in Windows. It runs fine until there is an 
unexpected error: I could find out that the return value of 
bufferevent_socket_connect is < 0 which never happened in Ubuntu before.

Do you know why the same function call returns 0 for Ubuntu and -1 for 
Windows? If you don't, do you know a way to get to know what went wrong?

I called WSAStartup and I allowed the program in the Windows built-in 
firewall.

I am using Libevent 2.0.21-stable.

Thank you for your time and best wishes, Andre.
***********************************************************************
To unsubscribe, send an e-mail to majordomo <at> freehaven.net with
unsubscribe libevent-users    in the body.

slump | 16 Jan 08:42 2015

unsend data in output buffer when close connection

 
I have used bufferevent to send data to socket
the application use variable length message, the first 4 bytes in message is the length
 
all thing is OK but for socket reconnect
 
if the socket is closed by peer and my app reconnect
peer may receive the wrong msg, the message length is  wrong
 
it seems the unsent data in bufferevent's output buffer will be send when the socket reconnect
but the message boundary is broken in output buffer
 
I guess it is because when I write message use bufferevent_write, one message is splited into two chunks in output buffer
one chunk is send to peer before socket closed
and the  next chunk is sent to peer after socket reconnect, so the message is broken
 
if it is true, can I get the data from output buffer and find the next message begin in data
so I can  discard the broken message and send the message follow it
 
but I find I can't get the data from output buffer, the evbuffer_copyout function return -1
 
and I can't find the function to clear the output buffer to discard all message in buffer
 
the only thing I can do is to free the bufferevent and create a new bufferevent when reconnect socket
 
is it the right way to do such thing?
 
Thank you!
 
2015-01-16
slump
Ralph Castain | 9 Jan 19:05 2015

Memory leak in locks?

Hi folks

I’ve trying to make a new library that uses libevent be valgrind clean. This is a threaded library, and so
libevent is thread enabled. I create a new event base, and I call event_base_free before finalizing.

However, I keep seeing reports like this:

==16029== 40 bytes in 1 blocks are still reachable in loss record 1 of 3
==16029==    at 0x4C288FE: malloc (in /home/common/local/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16029==    by 0x52A9EE1: evthread_posix_lock_alloc (evthread_pthread.c:46)
==16029==    by 0x5075572: event_global_setup_locks_ (event.c:2900)
==16029==    by 0x52AA08A: evthread_use_pthreads (evthread_pthread.c:185)

This is with libevent 2.0.22-stable. Is this an expected situation? Or is there something I need to do
beyond event_base_free to get a clean finalize?

Thanks
Ralph

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

Nick Mathewson | 5 Jan 16:32 2015
Picon

[ANN] Libevent 1.4.15-stable is released

Hello, all!

There are three new Libevent releases out today.  One of them is
1.4.15-stable, an updated oldstable release.  (I do not expect to do
any more 1.4 releases after this.)

This release fixes a moderately worrisome security issue in
evbuffers that could affect some programs; see
   http://archives.seul.org/libevent/users/Jan-2015/msg00010.html
for details.

You can get the source code from http://libevent.org or from one of
the git repositories.  If the website hasn't updated yet, you can
get the files from
    https://sourceforge.net/projects/levent/files/libevent/

As usual, make sure to check the GPG signatures on the source
distributions.

================================ Changes in 1.4.15-stable

Changes in 1.4.15-stable (5 January 2015)

 o Avoid integer overflow bugs in evbuffer_add() and related
functions.  See CVE-2014-6272 advisory for more information.
(d49bc0e88b81a5812116074dc007f1db0ca1eecd)

 o Pass flags to fcntl(F_SETFL) as int, not long (b3d0382)
 o Backport and tweak the LICENSE file for 1.4 (8a5ebd3)
 o set close-on-exec bit for filedescriptors created by dns subsystem
(9985231 Ralf Schmitt)
 o Replace unused case of FD_CLOSEONEXEC with a proper null statement. (44f04a2)
 o Fix kqueue correctness test on x84_64 (1c25b07)
 o Avoid deadlock when activating signals. (e0e6958)
 o Backport doc fix for evhttp_bind_socket. (95b71d0 Marco)
 o Fix an issue with forking and signal socketpairs in select/poll
backends (f0ff765)
 o Fix compilation on Visual Studio 2010 (53c47c2 VDm)
 o Defensive programming to prevent (hopefully impossible)
stack-stomping (2d8cf0b)
 o Check for POLLERR, POLLHUP and POLLNVAL for Solaris event ports
(353b4ac Trond Norbye)
 o Fix a bug that could allow dns requests with duplicate tx ids (e50ba5b)
 o Avoid truncating huge values for content-length (1d6e30e)
 o Take generated files out of git; add correct m4 magic for libtool
to auto* files (7cf794b)
 o Prefer autoregen -ivf to manual autogen.sh (823d9be)

================================ Acknowledgments

Thanks to everybody who contributed patches or bug reports or advice
to this release, including but not exclusively those mentioned
above.

Thanks also to everyone mentioned in the CVE-2014-6272 advisory.
***********************************************************************
To unsubscribe, send an e-mail to majordomo <at> freehaven.net with
unsubscribe libevent-users    in the body.


Gmane