416 changes: 416 additions & 0 deletions src/examples/epoll_event_manager.c

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions src/examples/event_manager.h
@@ -0,0 +1,74 @@
/*
This file is part of libmicrohttpd
Copyright (C) 2007 Christian Grothoff (and other contributing authors)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file event_manager.h
* @brief The generic event manager interface
* @author Simon Newton
*/

#ifndef EVENT_MANAGER_H
#define EVENT_MANAGER_H

#include <microhttpd.h>

/**
* @brief A generic EventManager.
*
* Implementations using epoll and kevent are provided.
*/
typedef struct EventManager EventManager;

/**
* @brief Create a new EventManager.
* @returns A new EventManager, or NULL if one couldn't be created.
*/
EventManager*
event_manager_init ();

/**
* @brief Enter the EventManager loop.
* @param em An EventManager.
* @returns 0 on clean exit, non-0 if an error occured.
*/
int
event_manager_loop (EventManager *em);

/**
* @brief Stop the EventManager loop.
* @param em An EventManager.
*/
void
event_manager_stop (EventManager *em);

/**
* @brief Fetch a pointer to the MHD_EventManager.
* @param em An EventManager.
* @returns A MHD_EventManager to be passed to MHD_start_daemon.
*/
MHD_EventManager*
event_manager_interface(EventManager *em);

/**
* @brief Destory an EventManager.
* @param em An EventManager.
*/
void
event_manager_cleanup (EventManager *em);

#endif
144 changes: 144 additions & 0 deletions src/examples/event_manager_example.c
@@ -0,0 +1,144 @@
/*
This file is part of libmicrohttpd
Copyright (C) 2007 Christian Grothoff (and other contributing authors)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file event_manager_example.c
* @brief minimal example for how to use libmicrohttpd with an external event
* manager.
* @author Christian Grothoff
*/

#include "platform.h"
#include <microhttpd.h>
#include <stdint.h>
#include "event_manager.h"

#define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>"

/* Test Certificate */
const char cert_pem[] =
"-----BEGIN CERTIFICATE-----\n"
"MIICpjCCAZCgAwIBAgIESEPtjjALBgkqhkiG9w0BAQUwADAeFw0wODA2MDIxMjU0\n"
"MzhaFw0wOTA2MDIxMjU0NDZaMAAwggEfMAsGCSqGSIb3DQEBAQOCAQ4AMIIBCQKC\n"
"AQC03TyUvK5HmUAirRp067taIEO4bibh5nqolUoUdo/LeblMQV+qnrv/RNAMTx5X\n"
"fNLZ45/kbM9geF8qY0vsPyQvP4jumzK0LOJYuIwmHaUm9vbXnYieILiwCuTgjaud\n"
"3VkZDoQ9fteIo+6we9UTpVqZpxpbLulBMh/VsvX0cPJ1VFC7rT59o9hAUlFf9jX/\n"
"GmKdYI79MtgVx0OPBjmmSD6kicBBfmfgkO7bIGwlRtsIyMznxbHu6VuoX/eVxrTv\n"
"rmCwgEXLWRZ6ru8MQl5YfqeGXXRVwMeXU961KefbuvmEPccgCxm8FZ1C1cnDHFXh\n"
"siSgAzMBjC/b6KVhNQ4KnUdZAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0O\n"
"BBYEFJcUvpjvE5fF/yzUshkWDpdYiQh/MAsGCSqGSIb3DQEBBQOCAQEARP7eKSB2\n"
"RNd6XjEjK0SrxtoTnxS3nw9sfcS7/qD1+XHdObtDFqGNSjGYFB3Gpx8fpQhCXdoN\n"
"8QUs3/5ZVa5yjZMQewWBgz8kNbnbH40F2y81MHITxxCe1Y+qqHWwVaYLsiOTqj2/\n"
"0S3QjEJ9tvklmg7JX09HC4m5QRYfWBeQLD1u8ZjA1Sf1xJriomFVyRLI2VPO2bNe\n"
"JDMXWuP+8kMC7gEvUnJ7A92Y2yrhu3QI3bjPk8uSpHea19Q77tul1UVBJ5g+zpH3\n"
"OsF5p0MyaVf09GTzcLds5nE/osTdXGUyHJapWReVmPm3Zn6gqYlnzD99z+DPIgIV\n"
"RhZvQx74NQnS6g==\n" "-----END CERTIFICATE-----\n";

const char key_pem[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEowIBAAKCAQEAtN08lLyuR5lAIq0adOu7WiBDuG4m4eZ6qJVKFHaPy3m5TEFf\n"
"qp67/0TQDE8eV3zS2eOf5GzPYHhfKmNL7D8kLz+I7psytCziWLiMJh2lJvb2152I\n"
"niC4sArk4I2rnd1ZGQ6EPX7XiKPusHvVE6VamacaWy7pQTIf1bL19HDydVRQu60+\n"
"faPYQFJRX/Y1/xpinWCO/TLYFcdDjwY5pkg+pInAQX5n4JDu2yBsJUbbCMjM58Wx\n"
"7ulbqF/3lca0765gsIBFy1kWeq7vDEJeWH6nhl10VcDHl1PetSnn27r5hD3HIAsZ\n"
"vBWdQtXJwxxV4bIkoAMzAYwv2+ilYTUOCp1HWQIDAQABAoIBAArOQv3R7gmqDspj\n"
"lDaTFOz0C4e70QfjGMX0sWnakYnDGn6DU19iv3GnX1S072ejtgc9kcJ4e8VUO79R\n"
"EmqpdRR7k8dJr3RTUCyjzf/C+qiCzcmhCFYGN3KRHA6MeEnkvRuBogX4i5EG1k5l\n"
"/5t+YBTZBnqXKWlzQLKoUAiMLPg0eRWh+6q7H4N7kdWWBmTpako7TEqpIwuEnPGx\n"
"u3EPuTR+LN6lF55WBePbCHccUHUQaXuav18NuDkcJmCiMArK9SKb+h0RqLD6oMI/\n"
"dKD6n8cZXeMBkK+C8U/K0sN2hFHACsu30b9XfdnljgP9v+BP8GhnB0nCB6tNBCPo\n"
"32srOwECgYEAxWh3iBT4lWqL6bZavVbnhmvtif4nHv2t2/hOs/CAq8iLAw0oWGZc\n"
"+JEZTUDMvFRlulr0kcaWra+4fN3OmJnjeuFXZq52lfMgXBIKBmoSaZpIh2aDY1Rd\n"
"RbEse7nQl9hTEPmYspiXLGtnAXW7HuWqVfFFP3ya8rUS3t4d07Hig8ECgYEA6ou6\n"
"OHiBRTbtDqLIv8NghARc/AqwNWgEc9PelCPe5bdCOLBEyFjqKiT2MttnSSUc2Zob\n"
"XhYkHC6zN1Mlq30N0e3Q61YK9LxMdU1vsluXxNq2rfK1Scb1oOlOOtlbV3zA3VRF\n"
"hV3t1nOA9tFmUrwZi0CUMWJE/zbPAyhwWotKyZkCgYEAh0kFicPdbABdrCglXVae\n"
"SnfSjVwYkVuGd5Ze0WADvjYsVkYBHTvhgRNnRJMg+/vWz3Sf4Ps4rgUbqK8Vc20b\n"
"AU5G6H6tlCvPRGm0ZxrwTWDHTcuKRVs+pJE8C/qWoklE/AAhjluWVoGwUMbPGuiH\n"
"6Gf1bgHF6oj/Sq7rv/VLZ8ECgYBeq7ml05YyLuJutuwa4yzQ/MXfghzv4aVyb0F3\n"
"QCdXR6o2IYgR6jnSewrZKlA9aPqFJrwHNR6sNXlnSmt5Fcf/RWO/qgJQGLUv3+rG\n"
"7kuLTNDR05azSdiZc7J89ID3Bkb+z2YkV+6JUiPq/Ei1+nDBEXb/m+/HqALU/nyj\n"
"P3gXeQKBgBusb8Rbd+KgxSA0hwY6aoRTPRt8LNvXdsB9vRcKKHUFQvxUWiUSS+L9\n"
"/Qu1sJbrUquKOHqksV5wCnWnAKyJNJlhHuBToqQTgKXjuNmVdYSe631saiI7PHyC\n"
"eRJ6DxULPxABytJrYCRrNqmXi5TCiqR2mtfalEMOPxz8rUU8dYyx\n"
"-----END RSA PRIVATE KEY-----\n";

static int
ahc_echo (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *version,
const char *upload_data, size_t *upload_data_size, void **ptr)
{
static int aptr;
const char *me = cls;
struct MHD_Response *response;
int ret;

if (0 != strcmp (method, "GET"))
return MHD_NO; /* unexpected method */
if (&aptr != *ptr)
{
/* do never respond on first call */
*ptr = &aptr;
return MHD_YES;
}
*ptr = NULL; /* reset when done */
response = MHD_create_response_from_buffer (strlen (me),
(void *) me,
MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;
}

int
main (int argc, char *const *argv)
{
struct EventManager *em = event_manager_init();

if (NULL == em)
return 1;

struct MHD_Daemon *d;

if (argc != 2)
{
printf ("%s PORT\n", argv[0]);
return 1;
}
d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL,
atoi (argv[1]),
NULL, NULL, &ahc_echo, PAGE,
MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 10,
MHD_OPTION_HTTPS_MEM_KEY, key_pem,
MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
MHD_OPTION_EXTERNAL_EVENT_MANAGER,
event_manager_interface(em),
MHD_OPTION_END);
if (d == NULL)
return 1;
if (event_manager_loop(em))
{
return 1;
}

event_manager_cleanup(em);
return 0;
}
446 changes: 446 additions & 0 deletions src/examples/kqueue_event_manager.c

Large diffs are not rendered by default.

146 changes: 145 additions & 1 deletion src/include/microhttpd.h
Expand Up @@ -935,7 +935,14 @@ enum MHD_OPTION
* pointer to a closure to pass to the request completed callback.
* The second pointer maybe NULL.
*/
MHD_OPTION_NOTIFY_CONNECTION = 27
MHD_OPTION_NOTIFY_CONNECTION = 27,

/**
* Register a MHD_EventManager object to handle events.
*
* This option should be followed by a pointer to a MHD_EventManager struct.
*/
MHD_OPTION_EXTERNAL_EVENT_MANAGER = 28

};

Expand Down Expand Up @@ -1489,6 +1496,143 @@ typedef int
uint64_t off,
size_t size);

/* **************** EventManager types ***************** */

/**
* @brief A watch handle.
* Watches are used to receive notifications when a file descriptor is ready
* for reading / writing.
*/
typedef struct MHD_Watch MHD_Watch;

/**
* @brief A timeout handle
*/
typedef struct MHD_Timeout MHD_Timeout;

/**
* @brief The EventManager interface.
*/
typedef struct MHD_EventManager MHD_EventManager;

/**
* @brief Type of watch events.
*/
typedef enum
{
MHD_WATCH_IN = 0x01, //!< Input event
MHD_WATCH_OUT = 0x02, //!< Output event
} MHD_WatchEvent;

/**
* @brief The function invoked when a watch event occurs.
* @param watch the Watch that triggered this event
* @param fd the file descriptor that triggered the event.
* @param event the type of event
* @param mhd_data The data provided when the watch was created.
*/
typedef void
(*MHD_WatchCallback)(MHD_Watch *watch,
int fd,
MHD_WatchEvent event,
void *mhd_data);

/**
* @brief The function invoked when a timeout event occurs.
* @param timeout The timeout that triggered the event.
* @param mhd_data The data provided when the timeout was created.
*/
typedef void
(*MHD_TimeoutCallback)(MHD_Timeout *timeout,
void *mhd_data);

/**
* @brief An abstracted external event management API.
*/
struct MHD_EventManager
{
/**
* @brief Opaque data used by the implementation of the EventManager.
*/
void *userdata;

/**
* @brief Called by MHD to create a new watch.
* @param em The MHD_EventManager passed to the MHD.
* @param fd The file descriptor to watch.
* @param event The type of events to watch for.
* @param callback The callback that will be run when any event occurs.
* @param mhd_data Opaque data that will be passed to the callback function
* when the event occurs.
* @returns A MHD_Watch.
*/
MHD_Watch*
(*watch_new)(const MHD_EventManager *em,
int fd,
MHD_WatchEvent events,
MHD_WatchCallback callback,
void *mhd_data);

/**
* @brief Update the set of events for a watch.
* @param watch The Watch to update
* @param events The new events to trigger on.
* @note Implementations must ensure this is safe to call from within a
* MHD_WatchCallback..
*/
void
(*watch_update)(MHD_Watch *watch,
MHD_WatchEvent events);

/**
* @brief Free a watch.
* @param watch The Watch to free.
* @note Implementations must ensure this is safe to call from within a
* MHD_WatchCallback..
*/
void
(*watch_free)(MHD_Watch *w);

/**
* @brief Create a new timeout.
* @param em The MHD_EventManager passed to the MHD.
* @param tv The absolute time when this timeout should trigger. If tv is
* NULL, the timeout will be disabled.
* @param callback The callback to run when the timeout event occurs.
* @param mhd_data Opaque data that will be passed to the callback function
* when the timeout occurs.
*
* When the timeout occurs, the callback function will be run and the timeout
* disabled. It can be re-enabled by calling timeout_update.
*/
MHD_Timeout*
(*timeout_new)(const MHD_EventManager *em,
const struct timeval *tv,
MHD_TimeoutCallback callback,
void *mhd_data);

/**
* @brief Update the expiration time for a timeout.
* @param timeout The timeout to update.
* @param tv The new time when this timeout should be triggered. If tv is
* NULL, the timeout will be disabled.
* @note Implementations must ensure this is safe to call from within a
* MHD_TimeoutCallback.
*/
void
(*timeout_update)(MHD_Timeout *timeout,
const struct timeval *tv);

/**
* @brief Free a timeout
* @param timeout The timeout to free.
* @note Implementations must ensure this is safe to call from within a
* MHD_TimeoutCallback.
*/
void
(*timeout_free)(MHD_Timeout *timeout);
};

/* **************** Daemon handling functions ***************** */

/**
Expand Down
15 changes: 15 additions & 0 deletions src/microhttpd/internal.h
Expand Up @@ -869,6 +869,16 @@ struct MHD_Connection
* Is the connection wanting to resume?
*/
int resuming;

/**
* The Watch associated with this connection.
*/
struct MHD_Watch *watch;

/**
* The Timeout associated with this connection.
*/
struct MHD_Timeout *timeout;
};

/**
Expand Down Expand Up @@ -1297,6 +1307,11 @@ struct MHD_Daemon
*/
unsigned int fastopen_queue_size;
#endif

/**
* The EventManager, if one was provided.
*/
MHD_EventManager *em;
};


Expand Down