3977 Commits

Author SHA1 Message Date
Nathan French
1af8017648
[core] re-order fields in struct event for memory efficiency
The sizeof `struct event` can reduced on both 32 bit and 64 bit systems
by moving the 4 bytes that make up `ev_events` and `ev_res` below `ev_fd`,
before `struct event_base * ev_base;` since our compiler wouldn't dare do
such a thing (it instead will pad twice, whereas it only needs to be padded
once)

```C
struct event {
                                                         /*  OFFS |  SZ   Bytes  | Total Bytes | START - END  */
    struct event_callback ev_evcallback;                 /*   0x0 |  40          | 40          | 0x0   - 0x28 */

    union {                                              /*  0x28 |  ----------- | ----------- | ------------ */
        TAILQ_ENTRY(event) ev_next_with_common_timeout;  /*       |       ((16)) |             |              */
        int min_heap_idx;                                /*       |       ((04)) |             |              */
    }   ev_timeout_pos;                                  /*       |  16          | 56          | 0x28  - 0x38 */
    int ev_fd;                                           /*  0x38 |  04          | 60          | 0x38  - 0x3c */
```

Since the next field is 8 bytes in length, and we are up to 60 bytes, `ev_fd` ends up being padded (4 more bytes on 64b).

```C
                              /* --- 1 byte gap HERE --->            1           | <61>                      */
                              /* --- 1 byte gap HERE --->            1           | <62>                      */
                              /* --- 1 byte gap HERE --->            1           | <63>                      */
                              /* --- 1 byte gap HERE --->            1           | <64>                      */
    struct event_base * ev_base;                         /*  0x3c |  8           | 68         | 0x3c - 0x40  */
    union {                                              /*  0x40 | ------------ | ---------- | ------------ */
        struct {                                         /*       | ------------ |            |              */
            LIST_ENTRY (event) ev_io_next;               /*       |       ((16+  |            |              */
            struct timeval ev_timeout;                   /*       |         16)) |            |              */
        } ev_io;                                         /*       | ((32))       |            |              */
        struct {                                         /*       | ------------ |            |              */
            LIST_ENTRY (event) ev_signal_next;           /*       |      ((16+   |            |              */
            short   ev_ncalls;                           /*       |        02+   |            |              */
            short * ev_pncalls;                          /*       |        08))  |            |              */
        } ev_signal;                                     /*       | ((26))       |            |              */
    } ev_;                                               /*  0x60 | 32           | 100        | 0x40 - 0x60  */

    short ev_events;                                     /*  0x60 | 2            | 102        | 0x60 - 0x62  */
    short ev_res;                                        /*  0x62 | 2            | 104        | 0x62 - 0x64  */
```

We now hit another line, `struct timeval` is 16 bytes on 64b arch, so we have 4 more bytes
of padding on `ev_res`.

```C
    /* --- 1 byte gap HERE --- */
    /* --- 1 byte gap HERE --- */
    /* --- 1 byte gap HERE --- */
    /* --- 1 byte gap HERE --- */
    struct timeval ev_timeout;                           /*  0x64 | 16           | 120        | 0x64 - 0x74  */
};
```

After moving `ev_events` and `ev_res` below `ev_fd` we have something
a bit more optimal:

```C
struct event2 {
                                                         /*  OFFS |  SZ / Bytes  | RSUM Bytes | START - END  */
    struct event_callback ev_evcallback;                 /*   0x0 | 40           | 40         | 0x0   - 0x28 */
    union {                                              /*  0x28 | ------------ | ---------- | ------------ */
        TAILQ_ENTRY(event) ev_next_with_common_timeout;  /*       |       ((16)) |            |              */
        int min_heap_idx;                                /*       |       ((04)) |            |              */
    } ev_timeout_pos;                                    /*       | 16           | 56         | 0x28  - 0x38 */
    int ev_fd;                                           /*  0x38 | 4            | 60         | 0x38  - 0x3c */
    short ev_events;                                     /*  0x3c | 2            | 62         | 0x3c  - 0x3e */
    short ev_res;                                        /*  0x3e | 2            | 64         | 0x3e  - 0x40 */

    struct event_base * ev_base;                         /*  0x40 | 8            | 74         | 0x40  - 0x48 */
    union {                                              /*  0x48 | ------------ | ---------- | ------------ */
        struct {                                         /*       | ------------ |            |              */
            LIST_ENTRY (event) ev_io_next;               /*       |        ((16+ |            |              */
            struct timeval ev_timeout;                   /*       |         16)) |            |              */
        } ev_io;                                         /*       | ((32))       |            |              */
        struct {                                         /*       | ------------ |            |              */
            LIST_ENTRY (event) ev_signal_next;           /*       |       ((16+  |            |              */
            short   ev_ncalls;                           /*       |         02+  |            |              */
            short * ev_pncalls;                          /*       |         08)) |            |              */
        } ev_signal;                                     /*       | ((26))       |            |              */
    } ev_;                                               /*       | 32           | 106        | 0x48 - 0x68  */
    struct timeval ev_timeout;                           /* 0x68  | 16           | 120        | 0x68 - 0x78  */
};
```

We still have a gap here, but the first was removed.

Again, we can save 8 bytes on both 32 and 64 word sizes (32/64 byte cacheline).

Below are the results for testing v2.1.6 -> master -> master + this patch (Release/-O3)

Code:

```C
  #include <event2/event.h>

  int
  main(int argc, char ** argv) {
      printf("%zu\n", event_get_struct_event_size());
      return 0;
  }
```

Branch: `master` (2.2.x)

```
  $ gcc -O3 -Wall -Wl,-R/usr/local/lib bleh.c -L/usr/local/lib -o bleh  -levent
  $ ldd bleh
      linux-vdso.so.1 =>  (0x00007ffc3df50000)
      libevent.so.2.2.0 => /usr/local/lib/libevent.so.2.2.0 (0x00007f91fd781000)
      libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f91fd3a1000)
      libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f91fd182000)
      /lib64/ld-linux-x86-64.so.2 (0x00007f91fdbcc000)
  $ ./bleh
  128
```

Release: `2.1.6`

```
  $ gcc -O3 bleh.c -o bleh  -levent
  $ ldd bleh
      linux-vdso.so.1 =>  (0x00007ffd43773000)
      libevent-2.1.so.6 => /usr/lib/x86_64-linux-gnu/libevent-2.1.so.6 (0x00007feb3add6000)
      libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007feb3a9f6000)
      libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007feb3a7d7000)
      /lib64/ld-linux-x86-64.so.2 (0x00007feb3b22a000)
  $ ./bleh
  128
```

Branch: `this one`

```
  $ gcc -O3 -Wl,-R./lib bleh.c -o bleh -L./lib -levent
  $ ldd bleh
      linux-vdso.so.1 =>  (0x00007ffff55f7000)
      libevent.so.2.2.0 => ./lib/libevent.so.2.2.0 (0x00007ff8e5c82000)
      libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff8e58a2000)
      libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff8e5683000)
      /lib64/ld-linux-x86-64.so.2 (0x00007ff8e60cd000)
  $ ./bleh
  120
```
2018-04-30 18:13:45 -04:00
Azat Khuzhin
23c2914f6b Notify event base if there are no more events, so it can exit without delay
Fixes: #623
2018-04-26 01:14:49 +03:00
Azat Khuzhin
accf383e04 Fix CheckFunctionExistsEx() cmake macro on win32
For example under mingw64 it could not detect that strtok_r() exists,
because it checks with:
  void *p = func_name;

And for this you need the function to be defined, so just sync our
CheckFunctionExistsEx.c with CheckFunctionExists.c from cmake (and later
we should drop them out) since it does correct things to detech
functions existence.

Also for WIN32 there is -FIwinsock2.h -FIws2tcpip.h, and I guess that is
not works for mingw gcc (since -F in gcc is framework, and in windows
-FI is like -include in gcc). But looks like we do not need them
already (due to fixed CheckFunctionExistsEx()).

Refs: #605
2018-04-26 01:14:49 +03:00
Azat Khuzhin
d1c8993c3c test/dns: install correct RLIMIT_NOFILE in bufferevent_connect_hostname_emfile
Otherwise poll() will fail with EINVAL:
       EINVAL The nfds value exceeds the RLIMIT_NOFILE value.

P.S. and cleanup this test a little, with early-return.

CI: https://travis-ci.org/libevent/libevent/jobs/370350426
2018-04-24 14:47:58 +03:00
Azat Khuzhin
da028dec49 travis-ci: allow tests under osx to fail (temporary, until we will fix them) 2018-04-24 02:56:42 +03:00
Azat Khuzhin
e4edc7fc27 test/http: cover evhttp_connection_get_addr() for incomming connections
Refs: #510
2018-04-24 02:46:39 +03:00
Greg Hazel
367cd9e5c2 Fix evhttp_connection_get_addr() fox incomming http connections
Install conn_address of the bufferevent on incomping http connections
(even though this is kind of subsytem violation, so let's fix it in a
simplest way and thinkg about long-term solution).

Fixes: #510
Closes: #595 (pick)
2018-04-24 02:29:17 +03:00
Azat Khuzhin
a3d8f2e093 test/dns: verify bufferevent_socket_connect() errorcb invoking if socket() fails
Refs: #600
2018-04-24 02:05:30 +03:00
Jesse Fang
f7bc133797 bufferevent_socket_connect{,_hostname}() missing event callback and use ret code
- When socket() failed in bufferevent_socket_connect() , the event
  callback should be called also in
  bufferevent_socket_connect_hostname().  eg. when use
  bufferevent_socket_connect_hostname() to resolve and connect an IP
  address but process have a smaller ulimit open files, socket() fails
  always but caller is not notified.

- Make bufferevent_socket_connect()'s behavior more consistent: function
  return error then no callback, function return ok then error passed by
  event callback.

Fixes: #597
Closes: #599
Closes: #600
2018-04-24 02:05:30 +03:00
Azat Khuzhin
623ef3ccdc test/dns: cleanup test_bufferevent_connect_hostname() 2018-04-24 02:05:30 +03:00
Azat Khuzhin
a5f19422fd Merge branch 'pull-628'
* pull-628:
  Give priority to the build directory headers
  Do not ship evconfig-private.h in dist archive

Closes: #628
2018-04-23 00:52:57 +03:00
Cristian Morales Vega
5d74565a96 Give priority to the build directory headers
Not changing anything right now AFAIK. But if for any reason in the
future we end up with two headers with the same name in the source and
build directories, chances are we want to use the one in the build
directory.
2018-04-23 00:52:10 +03:00
Cristian Morales Vega
0379eb4b5d Do not ship evconfig-private.h in dist archive
It will be generated by autotools, so there is not reason to include it.
And infact this breaks compilation with out-of-tree builds (VPATH),
since, for the quote form of the include directive, headers in the
directory of the file with the #include line have priority over those
named in -I options, the copy of evconfig-private.h from the source
directory had priority over the one in the build directory.
2018-04-23 00:52:10 +03:00
Azat Khuzhin
e2874d95af Adopt ignore rules for cmake + ninja
In case we have build directory differs from source directory there will be
bunch of files we should ignore, so just remove leading "/" for some or rules.
And fix others.
2018-04-23 00:38:19 +03:00
SuckShit
ab3224c3e6 Fix assert() condition in evbuffer_drain() for IOCP
In the case of iocp, in the for loop above, there is a situation where:
  remaining == chain->off == 0

And this happens due to CHAIN_PINNED_R() case (that is used only in
buffer_iocp.c)

Closes: #630 (picked)
2018-04-22 13:27:40 +03:00
The Gitter Badger
ba78ba9e8b Add Gitter badge 2018-04-16 02:10:59 +03:00
Philip Herron
0fa43c99fb cmake: ensure windows dll's are installed as well as lib files
Closes: #621
2018-04-09 00:15:03 +03:00
dpayne
791e3de0c3 Generating evdns_base_config_windows_nameservers docs on all platforms 2018-04-03 15:43:22 -07:00
dpayne
2c1562949c Fixing doxygen docs for evdns_base_search_clear when generated on non-windows machines 2018-04-03 15:17:51 -07:00
Bernard Spil
28b8075400 Fix build with LibreSSL 2.7
LibreSSL 2.7 implements OpenSSL 1.1 API except for BIO_get_init()

See also: https://bugs.freebsd.org/226900
Signed-off-by: Bernard Spil <brnrd@FreeBSD.org>
Closes: #617 (cherry-pick)
2018-04-02 23:13:28 +03:00
Philip Prindeville
33baa4e59f Avoid possible SEGVs in select() (in unit tests)
Per the POSIX definition of select():

http://pubs.opengroup.org/onlinepubs/009696699/functions/pselect.html

"Upon successful completion, the select() function may modify the object
pointed to by the timout argument."

If "struct timeval" pointer is a "static const", it could potentially
be allocated in a RO text segment.  The kernel would then try to copy
back the modified value (with the time remaining) into a read-only
address and SEGV.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
Closes: #614
2018-03-30 01:24:25 +03:00
Greg Hazel
4ba4873967 don't fail be_null_filter if bytes are copied
Otherwise it will not reset timeouts for the IO, but other things should
still works correctly.

Also evbuffer_remove_buffer() could return 0, due to empty buffers, for
example during flushing bufferevent, so let's count this is BEV_OK too.
2018-03-25 22:55:34 +03:00
Greg Hazel
4055081499 Call underlying bev ctrl GET_FD on filtered bufferevents
Fixes: #611
Fixes: #610
2018-03-25 22:38:25 +03:00
Azat Khuzhin
08a0d36607 Fix base unlocking in event_del() if event_base_set() runned in another thread
Image next situation:
  T1:                                        T2:
   event_del_()
     lock the event.ev_base.th_base_lock
     event_del_nolock_()                     event_set_base()
     unlock the event.ev_base.th_base_lock

In this case we will unlock the wrong base after event_del_nolock_()
returns, and deadlock is likely to happens, since event_base_set() do
not check any mutexes (due to it is possible to do this only if event is
not inserted anywhere).

So event_del_() has to cache the base before removing the event, and
cached base.th_base_lock after.
2018-02-28 07:26:11 +03:00
Azat Khuzhin
f0fd92f2c4 Convert event_debug_*() helpers from macros to static functions 2018-02-27 21:08:35 +03:00
stenn
1a448088e3 Provide Makefile variables LIBEVENT_{CFLAGS,CPPFLAGS,LDFLAGS}
This will allow a parent package to specify compiler, CPP, and linker
flags to a libevent built as a sub-package. Document this in
whatsnew-2.2.txt.

Picked-from: #506
Closes: #506
2018-02-24 20:53:38 +03:00
Azat Khuzhin
cd57e38c3f http: remove message in case !Content-Length and Connection!=close
Since [1] GET can have body, and hence for every incomming connection it
will print this error.

[1] db483e3b002b33890fc88cadd77f6fd1fccad2d2 ("Allow bodies for
GET/DELETE/OPTIONS/CONNECT")

Noticed-by: BotoX (irc)
Refs: #408
2018-02-20 12:12:19 +03:00
Azat Khuzhin
93913da1c4 buffer: fix incorrect unlock of the buffer mutex (for deferred callbacks)
TSAN reports:
  WARNING: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread) (pid=17111)
      #0 pthread_mutex_unlock /build/gcc/src/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:3621 (libtsan.so.0+0x00000003b71c)
      #1 evbuffer_add <null> (libevent_core-2.2.so.1+0x00000000ddb6)
      ...

    Mutex M392 (0x7b0c00000f00) created at:
      #0 pthread_mutex_init /build/gcc/src/gcc/libsanitizer/tsan/tsan_interceptors.cc:1117 (libtsan.so.0+0x0000000291af)
      #1 <null> <null> (libevent_pthreads-2.2.so.1+0x000000000d46)
      ...

$ addr2line -e /lib/libevent_core-2.2.so.1 0x00000000ddb6
/src/libevent/buffer.c:1815 (discriminator 1)

Introduced-in: ae2b84b2575be93d0aebba5c0b78453836f89f3c ("Replace
deferred_cbs with event_callback-based implementation.")
2018-02-12 19:54:27 +03:00
Dmitry Alimov
f24b28e4af
Fix typos in comments 2018-01-15 17:30:08 +03:00
Azat Khuzhin
61c2149268 http: fix leaks in evhttp_uriencode()
Fixes: #584
2018-01-09 21:47:57 +03:00
Azat Khuzhin
416b48ba7a Merge branch 'listener-immediate-close'
* listener-immediate-close:
  test/listener: cover immediate-close logic
  Immediately stop trying to accept more connections if listener disabled
2018-01-04 19:28:59 +03:00
Azat Khuzhin
cb6995cf78 test/listener: cover immediate-close logic 2018-01-04 19:27:35 +03:00
John Fremlin
e03cd0b7eb Immediately stop trying to accept more connections if listener disabled
This is a refined version of the logic previously in #578

The rationale is that the consumer of sockets may wish to temporarily
delay accepting for some reason (e.g. being out of file-descriptors).
The kernel will then queue them up. The kernel queue is bounded and
programs like NodeJS will actually try to quickly accept and then close
(as the current behaviour before this PR).

However, it seems that libevent should allow the user to choose whether
to accept and respond correctly if the listener is disabled.
2018-01-04 19:26:36 +03:00
Marcin Szewczyk
88a1abe809 Fixed last_with_datap description
Grammar and typo fix
2017-12-18 14:01:52 +01:00
John Fremlin
727bcea130 http: add callback to allow server to decline (and thereby close) incoming connections.
This is important, as otherwise clients can easily exhaust the file
descriptors available on a libevent HTTP server, which can cause
problems in other code which does not handle EMFILE well: for example,
see https://github.com/bitcoin/bitcoin/issues/11368

Closes: #578 (patch cherry picked)
2017-12-18 03:00:04 +03:00
Azat Khuzhin
6e5c15d095 Fix typo in cmake because of which EVENT__SIZEOF_SIZE_T was wrong
Fixes: #580
2017-12-16 23:28:41 +03:00
Greg Hazel
65eb529a9f CONNECT method only takes an authority 2017-12-11 01:03:29 +03:00
yongqing.jiao
6cce7458d0 If precise_time is false, we should not set EVENT_BASE_FLAG_PRECISE_TIMER
Fixes: 630f077c296de61c7b99ed83bf30de11e75e2740 ("Simple unit tests for
monotonic timers")
2017-12-11 00:10:23 +03:00
Azat Khuzhin
bc65ffc14c Merge branch 'evconnlistener-do-not-close-client-fd'
Fixes: #577

* evconnlistener-do-not-close-client-fd:
  listener: cover closing of fd in case evconnlistener_free() called from acceptcb
  Revert "Fix potential fd leak in listener_read_cb()"
2017-12-10 23:57:19 +03:00
Azat Khuzhin
8a460e385a listener: cover closing of fd in case evconnlistener_free() called from acceptcb 2017-12-10 23:56:58 +03:00
Azat Khuzhin
94eae336a2 Revert "Fix potential fd leak in listener_read_cb()"
This reverts commit a695a720cda892c270736d127333d73553842094.

@kgraefe:
  "I believe that this commit is just wrong: if lev->cnt is not 1 after
  the callback, new_fd will still never be closed in listener_read_cb().
  So in that case it is the responsibility of the user's code to close
  the file descriptor (which is fine). But why shouldn't it be in the
  other case? And how does the user's code know?"

And I agree
2017-12-10 23:55:51 +03:00
Andrey Okoshkin
6ee73ea9b0 Fix generation of LibeventConfig.cmake for the installation tree
'LIBEVENT_INCLUDE_DIRS' is properly initialized in 'LibeventConfig.cmake' as
'LibeventConfig.cmake.in' contains usage of 'LIBEVENT_CMAKE_DIR' and
'EVENT_INSTALL_INCLUDE_DIR' variables but not 'EVENT_CMAKE_DIR' and
'EVENT__INCLUDE_DIRS'.
Related typos are fixed.
2017-11-29 11:13:51 +03:00
Azat Khuzhin
c2c08e0203 Add missing includes into openssl-compat.h
Before it depends from the caller #include appropriate headers (at least
for OPENSSL_VERSION_NUMBER), but let's make it independent.

Fixes: #574
2017-11-22 10:35:01 +03:00
Azat Khuzhin
33e363f3df Free dns/event bases in dns-example to avoid leaks 2017-11-20 02:08:08 +03:00
ejurgensen
b49c70cc2e Fix incorrect ref to evhttp_get_decoded_uri in http.h
Replaces reference in the http.h include header file to evhttp_get_decoded_uri
with evhttp_uridecode. There is no function called evhttp_get_decoded_uri.
2017-11-05 12:18:49 +01:00
Azat Khuzhin
306747e51c Fix crashing http server when callback do not reply in place from *gencb*
This is the second hunk of the first patch
5ff8eb26371c4dc56f384b2de35bea2d87814779 ("Fix crashing http server when
callback do not reply in place")

Fixes: #567
2017-11-04 19:15:32 +03:00
lightningkay
3f19c5eb83 cmake doesn't has POLICY CMP0054 in low version 2017-11-04 18:57:00 +03:00
Azat Khuzhin
db483e3b00 Allow bodies for GET/DELETE/OPTIONS/CONNECT
I checked with nginx, and via it's lua bindings it allows body for all
this methods. Also everybody knows that some of web-servers allows body
for GET even though this is not RFC conformant.

Refs: #408
2017-10-30 11:32:13 +03:00
Andreas Gustafsson
99d0a952da Do not crash when evhttp_send_reply_start() is called after a timeout.
This fixes the crash reported in issue #509.  The "would be nice"
items discussed in #509 can be addressed separately.
2017-10-30 11:32:13 +03:00
Azat Khuzhin
5ff8eb2637 Fix crashing http server when callback do not reply in place
General http callback looks like:
  static void http_cb(struct evhttp_request *req, void *arg)
  {
    evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
  }

And they will work fine becuase in this case http will write request
first, and during write preparation it will disable *read callback* (in
evhttp_write_buffer()), but if we don't reply immediately, for example:
  static void http_cb(struct evhttp_request *req, void *arg)
  {
    return;
  }

This will leave connection in incorrect state, and if another request
will be written to the same connection libevent will abort with:
  [err] ../http.c: illegal connection state 7

Because it thinks that read for now is not possible, since there were no
write.

Fix this by disabling EV_READ entirely. We couldn't just reset callbacks
because this will leave EOF detection, which we don't need, since user
hasn't replied to callback yet.

Reported-by: Cory Fields <cory@coryfields.com>
2017-10-29 20:30:42 +03:00