GNU libmicrohttpd 0.9.5
|
00001 /* 00002 This file is part of libmicrohttpd 00003 (C) 2006, 2007, 2008, 2009, 2010, 2011 Christian Grothoff (and other contributing authors) 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00018 */ 00019 00072 #ifndef MHD_MICROHTTPD_H 00073 #define MHD_MICROHTTPD_H 00074 00075 #ifdef __cplusplus 00076 extern "C" 00077 { 00078 #if 0 /* keep Emacsens' auto-indent happy */ 00079 } 00080 #endif 00081 #endif 00082 00083 /* While we generally would like users to use a configure-driven 00084 build process which detects which headers are present and 00085 hence works on any platform, we use "standard" includes here 00086 to build out-of-the-box for beginning users on common systems. 00087 00088 Once you have a proper build system and go for more exotic 00089 platforms, you should define MHD_PLATFORM_H in some header that 00090 you always include *before* "microhttpd.h". Then the following 00091 "standard" includes won't be used (which might be a good 00092 idea, especially on platforms where they do not exist). */ 00093 #ifndef MHD_PLATFORM_H 00094 #include <unistd.h> 00095 #include <stdarg.h> 00096 #include <stdint.h> 00097 #ifdef __MINGW32__ 00098 #include <ws2tcpip.h> 00099 #else 00100 #include <sys/time.h> 00101 #include <sys/types.h> 00102 #include <sys/socket.h> 00103 #endif 00104 #endif 00105 00109 #define MHD_VERSION 0x00090700 00110 00114 #define MHD_YES 1 00115 00119 #define MHD_NO 0 00120 00124 #define MHD_INVALID_NONCE -1 00125 00130 #ifdef UINT64_MAX 00131 #define MHD_SIZE_UNKNOWN UINT64_MAX 00132 #else 00133 #define MHD_SIZE_UNKNOWN ((uint64_t) -1LL) 00134 #endif 00135 00136 #ifdef SIZE_MAX 00137 #define MHD_CONTENT_READER_END_OF_STREAM SIZE_MAX 00138 #define MHD_CONTENT_READER_END_WITH_ERROR (SIZE_MAX - 1) 00139 #else 00140 #define MHD_CONTENT_READER_END_OF_STREAM ((size_t) -1LL) 00141 #define MHD_CONTENT_READER_END_WITH_ERROR (((size_t) -1LL) - 1) 00142 #endif 00143 00149 #ifndef MHD_LONG_LONG 00150 #define MHD_LONG_LONG long long 00151 #endif 00152 #ifndef MHD_LONG_LONG_PRINTF 00153 00157 #define MHD_LONG_LONG_PRINTF "ll" 00158 #endif 00159 00160 00164 #define MHD_HTTP_CONTINUE 100 00165 #define MHD_HTTP_SWITCHING_PROTOCOLS 101 00166 #define MHD_HTTP_PROCESSING 102 00167 00168 #define MHD_HTTP_OK 200 00169 #define MHD_HTTP_CREATED 201 00170 #define MHD_HTTP_ACCEPTED 202 00171 #define MHD_HTTP_NON_AUTHORITATIVE_INFORMATION 203 00172 #define MHD_HTTP_NO_CONTENT 204 00173 #define MHD_HTTP_RESET_CONTENT 205 00174 #define MHD_HTTP_PARTIAL_CONTENT 206 00175 #define MHD_HTTP_MULTI_STATUS 207 00176 00177 #define MHD_HTTP_MULTIPLE_CHOICES 300 00178 #define MHD_HTTP_MOVED_PERMANENTLY 301 00179 #define MHD_HTTP_FOUND 302 00180 #define MHD_HTTP_SEE_OTHER 303 00181 #define MHD_HTTP_NOT_MODIFIED 304 00182 #define MHD_HTTP_USE_PROXY 305 00183 #define MHD_HTTP_SWITCH_PROXY 306 00184 #define MHD_HTTP_TEMPORARY_REDIRECT 307 00185 00186 #define MHD_HTTP_BAD_REQUEST 400 00187 #define MHD_HTTP_UNAUTHORIZED 401 00188 #define MHD_HTTP_PAYMENT_REQUIRED 402 00189 #define MHD_HTTP_FORBIDDEN 403 00190 #define MHD_HTTP_NOT_FOUND 404 00191 #define MHD_HTTP_METHOD_NOT_ALLOWED 405 00192 #define MHD_HTTP_METHOD_NOT_ACCEPTABLE 406 00193 #define MHD_HTTP_PROXY_AUTHENTICATION_REQUIRED 407 00194 #define MHD_HTTP_REQUEST_TIMEOUT 408 00195 #define MHD_HTTP_CONFLICT 409 00196 #define MHD_HTTP_GONE 410 00197 #define MHD_HTTP_LENGTH_REQUIRED 411 00198 #define MHD_HTTP_PRECONDITION_FAILED 412 00199 #define MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 413 00200 #define MHD_HTTP_REQUEST_URI_TOO_LONG 414 00201 #define MHD_HTTP_UNSUPPORTED_MEDIA_TYPE 415 00202 #define MHD_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE 416 00203 #define MHD_HTTP_EXPECTATION_FAILED 417 00204 #define MHD_HTTP_UNPROCESSABLE_ENTITY 422 00205 #define MHD_HTTP_LOCKED 423 00206 #define MHD_HTTP_FAILED_DEPENDENCY 424 00207 #define MHD_HTTP_UNORDERED_COLLECTION 425 00208 #define MHD_HTTP_UPGRADE_REQUIRED 426 00209 #define MHD_HTTP_RETRY_WITH 449 00210 00211 #define MHD_HTTP_INTERNAL_SERVER_ERROR 500 00212 #define MHD_HTTP_NOT_IMPLEMENTED 501 00213 #define MHD_HTTP_BAD_GATEWAY 502 00214 #define MHD_HTTP_SERVICE_UNAVAILABLE 503 00215 #define MHD_HTTP_GATEWAY_TIMEOUT 504 00216 #define MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED 505 00217 #define MHD_HTTP_VARIANT_ALSO_NEGOTIATES 506 00218 #define MHD_HTTP_INSUFFICIENT_STORAGE 507 00219 #define MHD_HTTP_BANDWIDTH_LIMIT_EXCEEDED 509 00220 #define MHD_HTTP_NOT_EXTENDED 510 00221 00227 #define MHD_ICY_FLAG ((uint32_t)(1 << 31)) 00228 00229 /* See also: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html */ 00230 #define MHD_HTTP_HEADER_ACCEPT "Accept" 00231 #define MHD_HTTP_HEADER_ACCEPT_CHARSET "Accept-Charset" 00232 #define MHD_HTTP_HEADER_ACCEPT_ENCODING "Accept-Encoding" 00233 #define MHD_HTTP_HEADER_ACCEPT_LANGUAGE "Accept-Language" 00234 #define MHD_HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges" 00235 #define MHD_HTTP_HEADER_AGE "Age" 00236 #define MHD_HTTP_HEADER_ALLOW "Allow" 00237 #define MHD_HTTP_HEADER_AUTHORIZATION "Authorization" 00238 #define MHD_HTTP_HEADER_CACHE_CONTROL "Cache-Control" 00239 #define MHD_HTTP_HEADER_CONNECTION "Connection" 00240 #define MHD_HTTP_HEADER_CONTENT_ENCODING "Content-Encoding" 00241 #define MHD_HTTP_HEADER_CONTENT_LANGUAGE "Content-Language" 00242 #define MHD_HTTP_HEADER_CONTENT_LENGTH "Content-Length" 00243 #define MHD_HTTP_HEADER_CONTENT_LOCATION "Content-Location" 00244 #define MHD_HTTP_HEADER_CONTENT_MD5 "Content-MD5" 00245 #define MHD_HTTP_HEADER_CONTENT_RANGE "Content-Range" 00246 #define MHD_HTTP_HEADER_CONTENT_TYPE "Content-Type" 00247 #define MHD_HTTP_HEADER_COOKIE "Cookie" 00248 #define MHD_HTTP_HEADER_DATE "Date" 00249 #define MHD_HTTP_HEADER_ETAG "ETag" 00250 #define MHD_HTTP_HEADER_EXPECT "Expect" 00251 #define MHD_HTTP_HEADER_EXPIRES "Expires" 00252 #define MHD_HTTP_HEADER_FROM "From" 00253 #define MHD_HTTP_HEADER_HOST "Host" 00254 #define MHD_HTTP_HEADER_IF_MATCH "If-Match" 00255 #define MHD_HTTP_HEADER_IF_MODIFIED_SINCE "If-Modified-Since" 00256 #define MHD_HTTP_HEADER_IF_NONE_MATCH "If-None-Match" 00257 #define MHD_HTTP_HEADER_IF_RANGE "If-Range" 00258 #define MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE "If-Unmodified-Since" 00259 #define MHD_HTTP_HEADER_LAST_MODIFIED "Last-Modified" 00260 #define MHD_HTTP_HEADER_LOCATION "Location" 00261 #define MHD_HTTP_HEADER_MAX_FORWARDS "Max-Forwards" 00262 #define MHD_HTTP_HEADER_PRAGMA "Pragma" 00263 #define MHD_HTTP_HEADER_PROXY_AUTHENTICATE "Proxy-Authenticate" 00264 #define MHD_HTTP_HEADER_PROXY_AUTHORIZATION "Proxy-Authorization" 00265 #define MHD_HTTP_HEADER_RANGE "Range" 00266 #define MHD_HTTP_HEADER_REFERER "Referer" 00267 #define MHD_HTTP_HEADER_RETRY_AFTER "Retry-After" 00268 #define MHD_HTTP_HEADER_SERVER "Server" 00269 #define MHD_HTTP_HEADER_SET_COOKIE "Set-Cookie" 00270 #define MHD_HTTP_HEADER_SET_COOKIE2 "Set-Cookie2" 00271 #define MHD_HTTP_HEADER_TE "TE" 00272 #define MHD_HTTP_HEADER_TRAILER "Trailer" 00273 #define MHD_HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding" 00274 #define MHD_HTTP_HEADER_UPGRADE "Upgrade" 00275 #define MHD_HTTP_HEADER_USER_AGENT "User-Agent" 00276 #define MHD_HTTP_HEADER_VARY "Vary" 00277 #define MHD_HTTP_HEADER_VIA "Via" 00278 #define MHD_HTTP_HEADER_WARNING "Warning" 00279 #define MHD_HTTP_HEADER_WWW_AUTHENTICATE "WWW-Authenticate" 00280 00285 #define MHD_HTTP_VERSION_1_0 "HTTP/1.0" 00286 #define MHD_HTTP_VERSION_1_1 "HTTP/1.1" 00287 00291 #define MHD_HTTP_METHOD_CONNECT "CONNECT" 00292 #define MHD_HTTP_METHOD_DELETE "DELETE" 00293 #define MHD_HTTP_METHOD_GET "GET" 00294 #define MHD_HTTP_METHOD_HEAD "HEAD" 00295 #define MHD_HTTP_METHOD_OPTIONS "OPTIONS" 00296 #define MHD_HTTP_METHOD_POST "POST" 00297 #define MHD_HTTP_METHOD_PUT "PUT" 00298 #define MHD_HTTP_METHOD_TRACE "TRACE" 00299 00304 #define MHD_HTTP_POST_ENCODING_FORM_URLENCODED "application/x-www-form-urlencoded" 00305 #define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA "multipart/form-data" 00306 00317 enum MHD_FLAG 00318 { 00322 MHD_NO_FLAG = 0, 00323 00329 MHD_USE_DEBUG = 1, 00330 00334 MHD_USE_SSL = 2, 00335 00339 MHD_USE_THREAD_PER_CONNECTION = 4, 00340 00344 MHD_USE_SELECT_INTERNALLY = 8, 00345 00350 MHD_USE_IPv6 = 16, 00351 00361 MHD_USE_PEDANTIC_CHECKS = 32, 00362 00368 MHD_USE_POLL = 64 00369 }; 00370 00375 enum MHD_OPTION 00376 { 00377 00382 MHD_OPTION_END = 0, 00383 00388 MHD_OPTION_CONNECTION_MEMORY_LIMIT = 1, 00389 00394 MHD_OPTION_CONNECTION_LIMIT = 2, 00395 00401 MHD_OPTION_CONNECTION_TIMEOUT = 3, 00402 00415 MHD_OPTION_NOTIFY_COMPLETED = 4, 00416 00427 MHD_OPTION_PER_IP_CONNECTION_LIMIT = 5, 00428 00434 MHD_OPTION_SOCK_ADDR = 6, 00435 00457 MHD_OPTION_URI_LOG_CALLBACK = 7, 00458 00465 MHD_OPTION_HTTPS_MEM_KEY = 8, 00466 00473 MHD_OPTION_HTTPS_MEM_CERT = 9, 00474 00480 MHD_OPTION_HTTPS_CRED_TYPE = 10, 00481 00486 MHD_OPTION_HTTPS_PRIORITIES = 11, 00487 00494 MHD_OPTION_LISTEN_SOCKET = 12, 00495 00508 MHD_OPTION_EXTERNAL_LOGGER = 13, 00509 00518 MHD_OPTION_THREAD_POOL_SIZE = 14, 00519 00539 MHD_OPTION_ARRAY = 15, 00540 00559 MHD_OPTION_UNESCAPE_CALLBACK = 16, 00560 00570 MHD_OPTION_DIGEST_AUTH_RANDOM = 17, 00571 00577 MHD_OPTION_NONCE_NC_SIZE = 18, 00578 00583 MHD_OPTION_THREAD_STACK_SIZE = 19, 00584 00590 MHD_OPTION_HTTPS_MEM_TRUST =20 00591 }; 00592 00593 00597 struct MHD_OptionItem 00598 { 00603 enum MHD_OPTION option; 00604 00610 intptr_t value; 00611 00616 void *ptr_value; 00617 00618 }; 00619 00620 00625 enum MHD_ValueKind 00626 { 00627 00631 MHD_RESPONSE_HEADER_KIND = 0, 00632 00636 MHD_HEADER_KIND = 1, 00637 00642 MHD_COOKIE_KIND = 2, 00643 00652 MHD_POSTDATA_KIND = 4, 00653 00657 MHD_GET_ARGUMENT_KIND = 8, 00658 00662 MHD_FOOTER_KIND = 16 00663 }; 00664 00669 enum MHD_RequestTerminationCode 00670 { 00671 00675 MHD_REQUEST_TERMINATED_COMPLETED_OK = 0, 00676 00682 MHD_REQUEST_TERMINATED_WITH_ERROR = 1, 00683 00689 MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 2, 00690 00695 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3 00696 00697 }; 00698 00699 00704 enum MHD_ConnectionInfoType 00705 { 00710 MHD_CONNECTION_INFO_CIPHER_ALGO, 00711 00716 MHD_CONNECTION_INFO_PROTOCOL, 00717 00724 MHD_CONNECTION_INFO_CLIENT_ADDRESS, 00725 00729 MHD_CONNECTION_INFO_GNUTLS_SESSION, 00730 00734 MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT 00735 00736 }; 00737 00742 enum MHD_DaemonInfoType 00743 { 00750 MHD_DAEMON_INFO_KEY_SIZE, 00751 00758 MHD_DAEMON_INFO_MAC_KEY_SIZE, 00759 00764 MHD_DAEMON_INFO_LISTEN_FD 00765 }; 00766 00767 00768 00772 struct MHD_Daemon; 00773 00780 struct MHD_Connection; 00781 00785 struct MHD_Response; 00786 00790 struct MHD_PostProcessor; 00791 00799 typedef void (*MHD_PanicCallback) (void *cls, 00800 const char *file, 00801 unsigned int line, 00802 const char *reason); 00803 00811 typedef int 00812 (*MHD_AcceptPolicyCallback) (void *cls, 00813 const struct sockaddr * addr, 00814 socklen_t addrlen); 00815 00851 typedef int 00852 (*MHD_AccessHandlerCallback) (void *cls, 00853 struct MHD_Connection * connection, 00854 const char *url, 00855 const char *method, 00856 const char *version, 00857 const char *upload_data, 00858 size_t *upload_data_size, 00859 void **con_cls); 00860 00872 typedef void 00873 (*MHD_RequestCompletedCallback) (void *cls, 00874 struct MHD_Connection * connection, 00875 void **con_cls, 00876 enum MHD_RequestTerminationCode toe); 00877 00888 typedef int 00889 (*MHD_KeyValueIterator) (void *cls, 00890 enum MHD_ValueKind kind, 00891 const char *key, const char *value); 00892 00940 typedef ssize_t 00941 (*MHD_ContentReaderCallback) (void *cls, 00942 uint64_t pos, 00943 char *buf, 00944 size_t max); 00945 00952 typedef void (*MHD_ContentReaderFreeCallback) (void *cls); 00953 00973 typedef int 00974 (*MHD_PostDataIterator) (void *cls, 00975 enum MHD_ValueKind kind, 00976 const char *key, 00977 const char *filename, 00978 const char *content_type, 00979 const char *transfer_encoding, 00980 const char *data, uint64_t off, size_t size); 00981 00982 /* **************** Daemon handling functions ***************** */ 00983 01000 struct MHD_Daemon *MHD_start_daemon_va (unsigned int options, 01001 uint16_t port, 01002 MHD_AcceptPolicyCallback apc, 01003 void *apc_cls, 01004 MHD_AccessHandlerCallback dh, 01005 void *dh_cls, va_list ap); 01006 01022 struct MHD_Daemon *MHD_start_daemon (unsigned int flags, 01023 uint16_t port, 01024 MHD_AcceptPolicyCallback apc, 01025 void *apc_cls, 01026 MHD_AccessHandlerCallback dh, 01027 void *dh_cls, ...); 01028 01034 void MHD_stop_daemon (struct MHD_Daemon *daemon); 01035 01036 01050 int 01051 MHD_get_fdset (struct MHD_Daemon *daemon, 01052 fd_set * read_fd_set, 01053 fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd); 01054 01067 int MHD_get_timeout (struct MHD_Daemon *daemon, 01068 unsigned MHD_LONG_LONG *timeout); 01069 01070 01082 int MHD_run (struct MHD_Daemon *daemon); 01083 01084 01085 /* **************** Connection handling functions ***************** */ 01086 01097 int 01098 MHD_get_connection_values (struct MHD_Connection *connection, 01099 enum MHD_ValueKind kind, 01100 MHD_KeyValueIterator iterator, void *iterator_cls); 01101 01131 int 01132 MHD_set_connection_value (struct MHD_Connection *connection, 01133 enum MHD_ValueKind kind, 01134 const char *key, const char *value); 01135 01151 void MHD_set_panic_func (MHD_PanicCallback cb, void *cls); 01152 01162 const char *MHD_lookup_connection_value (struct MHD_Connection *connection, 01163 enum MHD_ValueKind kind, 01164 const char *key); 01165 01176 int 01177 MHD_queue_response (struct MHD_Connection *connection, 01178 unsigned int status_code, struct MHD_Response *response); 01179 01180 01181 /* **************** Response manipulation functions ***************** */ 01182 01198 struct MHD_Response *MHD_create_response_from_callback (uint64_t size, 01199 size_t block_size, 01200 MHD_ContentReaderCallback 01201 crc, void *crc_cls, 01202 MHD_ContentReaderFreeCallback 01203 crfc); 01204 01205 01206 01220 struct MHD_Response *MHD_create_response_from_data (size_t size, 01221 void *data, 01222 int must_free, 01223 int must_copy); 01224 01225 01230 enum MHD_ResponseMemoryMode { 01231 01237 MHD_RESPMEM_PERSISTENT, 01238 01244 MHD_RESPMEM_MUST_FREE, 01245 01252 MHD_RESPMEM_MUST_COPY 01253 01254 }; 01255 01256 01266 struct MHD_Response * 01267 MHD_create_response_from_buffer (size_t size, 01268 void *buffer, 01269 enum MHD_ResponseMemoryMode mode); 01270 01271 01281 struct MHD_Response *MHD_create_response_from_fd (size_t size, 01282 int fd); 01283 01284 01294 struct MHD_Response *MHD_create_response_from_fd_at_offset (size_t size, 01295 int fd, 01296 off_t offset); 01297 01298 01307 void MHD_destroy_response (struct MHD_Response *response); 01308 01318 int 01319 MHD_add_response_header (struct MHD_Response *response, 01320 const char *header, const char *content); 01321 01322 01331 int 01332 MHD_add_response_footer (struct MHD_Response *response, 01333 const char *footer, const char *content); 01334 01335 01344 int 01345 MHD_del_response_header (struct MHD_Response *response, 01346 const char *header, const char *content); 01347 01357 int 01358 MHD_get_response_headers (struct MHD_Response *response, 01359 MHD_KeyValueIterator iterator, void *iterator_cls); 01360 01361 01369 const char *MHD_get_response_header (struct MHD_Response *response, 01370 const char *key); 01371 01372 01373 /* ********************** PostProcessor functions ********************** */ 01374 01398 struct MHD_PostProcessor *MHD_create_post_processor (struct MHD_Connection 01399 *connection, 01400 size_t buffer_size, 01401 MHD_PostDataIterator 01402 iter, void *cls); 01403 01418 int 01419 MHD_post_process (struct MHD_PostProcessor *pp, 01420 const char *post_data, size_t post_data_len); 01421 01431 int MHD_destroy_post_processor (struct MHD_PostProcessor *pp); 01432 01433 01434 /* ********************* Digest Authentication functions *************** */ 01435 01436 01441 #define MHD_INVALID_NONCE -1 01442 01443 01451 char * 01452 MHD_digest_auth_get_username (struct MHD_Connection *connection); 01453 01454 01467 int 01468 MHD_digest_auth_check (struct MHD_Connection *connection, 01469 const char *realm, 01470 const char *username, 01471 const char *password, 01472 unsigned int nonce_timeout); 01473 01474 01488 int 01489 MHD_queue_auth_fail_response (struct MHD_Connection *connection, 01490 const char *realm, 01491 const char *opaque, 01492 struct MHD_Response *response, 01493 int signal_stale); 01494 01495 01504 char * 01505 MHD_basic_auth_get_username_password(struct MHD_Connection *connection, 01506 char** password); 01507 01515 int 01516 MHD_queue_basic_auth_fail_response(struct MHD_Connection *connection, 01517 const char *realm, 01518 struct MHD_Response *response); 01519 01520 /* ********************** generic query functions ********************** */ 01521 01525 union MHD_ConnectionInfo 01526 { 01527 01531 int /* enum gnutls_cipher_algorithm */ cipher_algorithm; 01532 01536 int /* enum gnutls_protocol */ protocol; 01537 01541 void * /* gnutls_session_t */ tls_session; 01542 01546 void * /* gnutls_x509_crt_t */ client_cert; 01547 01551 struct sockaddr *client_addr; 01552 }; 01553 01563 const union MHD_ConnectionInfo *MHD_get_connection_info (struct MHD_Connection 01564 *connection, 01565 enum 01566 MHD_ConnectionInfoType 01567 infoType, ...); 01568 01569 01573 union MHD_DaemonInfo 01574 { 01578 size_t key_size; 01579 01583 size_t mac_key_size; 01584 01588 int listen_fd; 01589 }; 01590 01601 const union MHD_DaemonInfo *MHD_get_daemon_info (struct MHD_Daemon *daemon, 01602 enum MHD_DaemonInfoType 01603 infoType, ...); 01604 01610 const char* MHD_get_version(void); 01611 01612 #if 0 /* keep Emacsens' auto-indent happy */ 01613 { 01614 #endif 01615 #ifdef __cplusplus 01616 } 01617 #endif 01618 01619 #endif