Advertisement
Guest User

libevent bufferevent output size

a guest
Jun 24th, 2011
225
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.91 KB | None | 0 0
  1.  /*
  2.  *
  3.  * Demonstrates problematic libevent behavior while trying to constrain size of output buffer
  4.  *
  5.  * Compile with:
  6.  * gcc -Wall `pkg-config --cflags --libs libevent` -o server server.c
  7.  *
  8.  * Run with:
  9.  * ./server
  10.  *
  11.  * In another terminal:
  12.  * yes | nc localhost 6565
  13.  *
  14.  * Notice the output the server produces - and after a while the output callback is no longer called
  15.  *
  16.  * Mina Naguib, 2011
  17.  */
  18.  
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <errno.h>
  22. #include <string.h>
  23. #include <time.h>
  24.  
  25. #include <sys/socket.h>
  26. #include <netinet/in.h>
  27. #include <arpa/inet.h>
  28.  
  29. #include <event.h>
  30. #include <event2/bufferevent.h>
  31. #include <event2/listener.h>
  32.  
  33. #define PORT 6565
  34. #define MAX_INPUT_BUFFER_SIZE 8192
  35. #define MAX_OUTPUT_BUFFER_SIZE 10240
  36.  
  37. char *
  38. now() {
  39.     time_t now = time(NULL);
  40.     char *n = ctime(&now);
  41.     char *temp;
  42.  
  43.     if ((temp = strchr(n, '\n'))) *temp = '\0';
  44.  
  45.     return n;
  46. }
  47.  
  48. void
  49. handle_client_buffer_in(struct bufferevent *bev, void *hint) {
  50.     struct evbuffer *input = bufferevent_get_input(bev);
  51.     struct evbuffer *output = bufferevent_get_output(bev);
  52.     size_t inlen = evbuffer_get_length(input), outlen = evbuffer_get_length(output);
  53.     size_t len;
  54.     char *line;
  55.     char *response;
  56.  
  57.     printf("[%s] BEV IN CALLED.  BEV LENGTHS: IN [%d] OUT [%d]\n", now(), (int)inlen, (int)outlen);
  58.  
  59.     if (outlen >= MAX_OUTPUT_BUFFER_SIZE) {
  60.         // Libevent will make sure the input buffer doesn't keep growing, but it's up to us
  61.         // to not write too much to the output buffer. We do that by refusing to drain the input buffer
  62.         return;
  63.     }
  64.  
  65.     while ((line = evbuffer_readln(input, &len, EVBUFFER_EOL_CRLF))) {
  66.         free(line);
  67.         response = "WELCOME TO MIAMI\n";
  68.         len = strlen(response);
  69.         evbuffer_add(output, response, len);
  70.     }
  71.  
  72. }
  73.  
  74. void
  75. handle_client_buffer_out(struct bufferevent *bev, void *hint) {
  76.     struct evbuffer *input = bufferevent_get_input(bev);
  77.     struct evbuffer *output = bufferevent_get_output(bev);
  78.     size_t inlen = evbuffer_get_length(input), outlen = evbuffer_get_length(output);
  79.  
  80.     printf("[%s] BEV OUT CALLED.  BEV LENGTHS: IN [%d] OUT [%d]\n", now(), (int)inlen, (int)outlen);
  81.  
  82.     // We can now start reading again
  83.     if (inlen > 0) handle_client_buffer_in(bev, hint);
  84.  
  85. }
  86.  
  87. void
  88. handle_client_buffer_evt(struct bufferevent *bev, short revents, void *hint) {
  89.  
  90.     if (revents & BEV_EVENT_ERROR) {
  91.         printf("Client error: %s\n", strerror(errno));
  92.         bufferevent_free(bev);
  93.     }
  94.     else if (revents & BEV_EVENT_TIMEOUT) {
  95.         printf("Client timed out\n");
  96.         bufferevent_free(bev);
  97.     }
  98.     else if (revents & BEV_EVENT_EOF) {
  99.         printf("Client disconnected\n");
  100.         bufferevent_free(bev);
  101.     }
  102.     else {
  103.         printf("Spurious event from client: %d\n", revents);
  104.         bufferevent_free(bev);
  105.     }
  106. }
  107.  
  108. void
  109. handle_new_client(struct evconnlistener *listener, evutil_socket_t client_fd, struct sockaddr *addr, int len, void *ptr) {
  110.  
  111.     struct bufferevent * bev;
  112.  
  113.     printf("Client connected\n");
  114.  
  115.     bev = bufferevent_socket_new(evconnlistener_get_base(listener), client_fd, BEV_OPT_CLOSE_ON_FREE);
  116.     bufferevent_setcb(
  117.             bev,
  118.             handle_client_buffer_in,
  119.             handle_client_buffer_out,
  120.             handle_client_buffer_evt,
  121.             NULL
  122.             );
  123.     bufferevent_setwatermark(bev, EV_READ, 0, MAX_INPUT_BUFFER_SIZE);
  124.     bufferevent_enable(bev, EV_READ);
  125.  
  126.  
  127. }
  128.  
  129. int main(int argc, char ** argv) {
  130.  
  131.     struct evconnlistener * server_listener;
  132.     struct event_base *eb = NULL;
  133.     struct sockaddr_in sa;
  134.  
  135.     eb = event_base_new();
  136.  
  137.     memset(&sa, 0, sizeof(sa));
  138.     sa.sin_family = AF_INET;
  139.     sa.sin_addr.s_addr = htonl(INADDR_ANY);
  140.     sa.sin_port = htons(PORT);
  141.  
  142.     server_listener = evconnlistener_new_bind(
  143.             eb,
  144.             handle_new_client,
  145.             NULL,
  146.             LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
  147.             -1,
  148.             (struct sockaddr *)&sa,
  149.             sizeof(sa)
  150.             );
  151.  
  152.     if (server_listener != NULL) {
  153.         printf("Server listening on port %d\n", PORT);
  154.         event_base_dispatch(eb);
  155.         return 0;
  156.     }
  157.     else {
  158.         printf("Could not get server going...\n");
  159.         return 1;
  160.     }
  161.  
  162. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement