diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-03-04 09:33:32 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-03-04 09:33:32 +0000 |
commit | f7ae5a3412f828cb9a7622f21b28b584b65adc32 (patch) | |
tree | bea91693cf3ab1e18d14f86d8434b331193b1c3f | |
parent | 45a0a30893f77a38a8add8a64c3650387840a335 (diff) | |
download | libmicrohttpd-f7ae5a3412f828cb9a7622f21b28b584b65adc32.tar.gz libmicrohttpd-f7ae5a3412f828cb9a7622f21b28b584b65adc32.zip |
adding API to handle #1661 (allow externally created connections)
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | doc/microhttpd-tutorial.texi | 4 | ||||
-rw-r--r-- | doc/microhttpd.texi | 32 | ||||
-rw-r--r-- | src/daemon/daemon.c | 146 | ||||
-rw-r--r-- | src/include/microhttpd.h | 29 |
6 files changed, 163 insertions, 58 deletions
@@ -1,3 +1,9 @@ | |||
1 | Fri Mar 4 10:24:04 CET 2011 | ||
2 | Added new API to allow MHD server to initiate connection to | ||
3 | client (special use-case for servers behind NAT), thereby | ||
4 | addressing #1661 (externally created connections). | ||
5 | Releasing libmicrohttpd 0.9.8. -CG | ||
6 | |||
1 | Fri Mar 4 10:07:18 CET 2011 | 7 | Fri Mar 4 10:07:18 CET 2011 |
2 | Avoid using a pipe for signalling as well, just use server | 8 | Avoid using a pipe for signalling as well, just use server |
3 | socket shutdown (also for thread-per-connection). -CG | 9 | socket shutdown (also for thread-per-connection). -CG |
diff --git a/configure.ac b/configure.ac index 1b136cf6..b79ee827 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -27,9 +27,9 @@ AM_CONFIG_HEADER([MHD_config.h]) | |||
27 | AC_CONFIG_MACRO_DIR([m4]) | 27 | AC_CONFIG_MACRO_DIR([m4]) |
28 | AH_TOP([#define _GNU_SOURCE 1]) | 28 | AH_TOP([#define _GNU_SOURCE 1]) |
29 | 29 | ||
30 | LIB_VERSION_CURRENT=15 | 30 | LIB_VERSION_CURRENT=16 |
31 | LIB_VERSION_REVISION=0 | 31 | LIB_VERSION_REVISION=0 |
32 | LIB_VERSION_AGE=5 | 32 | LIB_VERSION_AGE=6 |
33 | AC_SUBST(LIB_VERSION_CURRENT) | 33 | AC_SUBST(LIB_VERSION_CURRENT) |
34 | AC_SUBST(LIB_VERSION_REVISION) | 34 | AC_SUBST(LIB_VERSION_REVISION) |
35 | AC_SUBST(LIB_VERSION_AGE) | 35 | AC_SUBST(LIB_VERSION_AGE) |
diff --git a/doc/microhttpd-tutorial.texi b/doc/microhttpd-tutorial.texi index b4f19a34..020b1e2a 100644 --- a/doc/microhttpd-tutorial.texi +++ b/doc/microhttpd-tutorial.texi | |||
@@ -3,8 +3,8 @@ | |||
3 | @setfilename microhttpd-tutorial.info | 3 | @setfilename microhttpd-tutorial.info |
4 | @set UPDATED 28 Feb 2010 | 4 | @set UPDATED 28 Feb 2010 |
5 | @set UPDATED-MONTH Feb 2010 | 5 | @set UPDATED-MONTH Feb 2010 |
6 | @set EDITION 0.9.7 | 6 | @set EDITION 0.9.8 |
7 | @set VERSION 0.9.7 | 7 | @set VERSION 0.9.8 |
8 | @settitle A tutorial for GNU libmicrohttpd | 8 | @settitle A tutorial for GNU libmicrohttpd |
9 | 9 | ||
10 | @dircategory GNU Libraries | 10 | @dircategory GNU Libraries |
diff --git a/doc/microhttpd.texi b/doc/microhttpd.texi index 86ed2481..ab8c5c9e 100644 --- a/doc/microhttpd.texi +++ b/doc/microhttpd.texi | |||
@@ -9,7 +9,7 @@ header file @file{microhttpd.h}. | |||
9 | 9 | ||
10 | @noindent | 10 | @noindent |
11 | 11 | ||
12 | Copyright @copyright{} 2007, 2008, 2009, 2010 Christian Grothoff | 12 | Copyright @copyright{} 2007, 2008, 2009, 2010, 2011 Christian Grothoff |
13 | 13 | ||
14 | @quotation | 14 | @quotation |
15 | Permission is granted to copy, distribute and/or modify this document | 15 | Permission is granted to copy, distribute and/or modify this document |
@@ -1100,6 +1100,36 @@ started with the right options for this call. | |||
1100 | @end deftypefun | 1100 | @end deftypefun |
1101 | 1101 | ||
1102 | 1102 | ||
1103 | @deftypefun void MHD_add_connection (struct MHD_Daemon *daemon, int client_socket, const struct sockaddr *addr, socklen_t addrlen) | ||
1104 | Add another client connection to the set of connections | ||
1105 | managed by MHD. This API is usually not needed (since | ||
1106 | MHD will accept inbound connections on the server socket). | ||
1107 | Use this API in special cases, for example if your HTTP | ||
1108 | server is behind NAT and needs to connect out to the | ||
1109 | HTTP client. | ||
1110 | |||
1111 | The given client socket will be managed (and closed!) by MHD after | ||
1112 | this call and must no longer be used directly by the application | ||
1113 | afterwards. | ||
1114 | |||
1115 | @table @var | ||
1116 | @item daemon | ||
1117 | daemon that manages the connection | ||
1118 | @item client_socket | ||
1119 | socket to manage (MHD will expect to receive an HTTP request from this socket next). | ||
1120 | @item addr | ||
1121 | IP address of the client | ||
1122 | @item addrlen | ||
1123 | number of bytes in addr | ||
1124 | @end table | ||
1125 | |||
1126 | This function will return @code{MHD_YES} on success, | ||
1127 | @code{MHD_NO} if this daemon could | ||
1128 | not handle the connection (i.e. malloc failed, etc). | ||
1129 | The socket will be closed in any case. | ||
1130 | @end deftypefun | ||
1131 | |||
1132 | |||
1103 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 1133 | @c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1104 | 1134 | ||
1105 | @c ----------------------------------------------------------- | 1135 | @c ----------------------------------------------------------- |
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index f12f8207..54b73f9b 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c | |||
@@ -860,60 +860,52 @@ create_thread (pthread_t * thread, | |||
860 | 860 | ||
861 | 861 | ||
862 | /** | 862 | /** |
863 | * Accept an incoming connection and create the MHD_Connection object for | 863 | * Add another client connection to the set of connections |
864 | * it. This function also enforces policy by way of checking with the | 864 | * managed by MHD. This API is usually not needed (since |
865 | * accept policy callback. | 865 | * MHD will accept inbound connections on the server socket). |
866 | * | 866 | * Use this API in special cases, for example if your HTTP |
867 | * @param daemon handle with the listen socket | 867 | * server is behind NAT and needs to connect out to the |
868 | * @return MHD_YES on success | 868 | * HTTP client. |
869 | * | ||
870 | * The given client socket will be managed (and closed!) by MHD after | ||
871 | * this call and must no longer be used directly by the application | ||
872 | * afterwards. | ||
873 | * | ||
874 | * Per-IP connection limits are ignored when using this API. | ||
875 | * | ||
876 | * @param daemon daemon that manages the connection | ||
877 | * @param client_socket socket to manage (MHD will expect | ||
878 | * to receive an HTTP request from this socket next). | ||
879 | * @param addr IP address of the client | ||
880 | * @param addrlen number of bytes in addr | ||
881 | * @return MHD_YES on success, MHD_NO if this daemon could | ||
882 | * not handle the connection (i.e. malloc failed, etc). | ||
883 | * The socket will be closed in any case. | ||
869 | */ | 884 | */ |
870 | static int | 885 | int |
871 | MHD_accept_connection (struct MHD_Daemon *daemon) | 886 | MHD_add_connection (struct MHD_Daemon *daemon, |
887 | int client_socket, | ||
888 | const struct sockaddr *addr, | ||
889 | socklen_t addrlen) | ||
872 | { | 890 | { |
873 | struct MHD_Connection *connection; | 891 | struct MHD_Connection *connection; |
874 | #if HAVE_INET6 | ||
875 | struct sockaddr_in6 addrstorage; | ||
876 | #else | ||
877 | struct sockaddr_in addrstorage; | ||
878 | #endif | ||
879 | struct sockaddr *addr = (struct sockaddr *) &addrstorage; | ||
880 | socklen_t addrlen; | ||
881 | int s; | ||
882 | int res_thread_create; | 892 | int res_thread_create; |
883 | #if OSX | 893 | #if OSX |
884 | static int on = 1; | 894 | static int on = 1; |
885 | #endif | 895 | #endif |
886 | 896 | ||
887 | addrlen = sizeof (addrstorage); | ||
888 | memset (addr, 0, sizeof (addrstorage)); | ||
889 | |||
890 | s = ACCEPT (daemon->socket_fd, addr, &addrlen); | ||
891 | if ((s == -1) || (addrlen <= 0)) | ||
892 | { | ||
893 | #if HAVE_MESSAGES | ||
894 | /* This could be a common occurance with multiple worker threads */ | ||
895 | if ((EAGAIN != errno) && (EWOULDBLOCK != errno)) | ||
896 | MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); | ||
897 | #endif | ||
898 | if (s != -1) | ||
899 | { | ||
900 | SHUTDOWN (s, SHUT_RDWR); | ||
901 | CLOSE (s); | ||
902 | /* just in case */ | ||
903 | } | ||
904 | return MHD_NO; | ||
905 | } | ||
906 | #ifndef WINDOWS | 897 | #ifndef WINDOWS |
907 | if ( (s >= FD_SETSIZE) && | 898 | if ( (client_socket >= FD_SETSIZE) && |
908 | (0 == (daemon->options & MHD_USE_POLL)) ) | 899 | (0 == (daemon->options & MHD_USE_POLL)) ) |
909 | { | 900 | { |
910 | #if HAVE_MESSAGES | 901 | #if HAVE_MESSAGES |
911 | MHD_DLOG (daemon, | 902 | MHD_DLOG (daemon, |
912 | "Socket descriptor larger than FD_SETSIZE: %d > %d\n", | 903 | "Socket descriptor larger than FD_SETSIZE: %d > %d\n", |
913 | s, | 904 | client_socket, |
914 | FD_SETSIZE); | 905 | FD_SETSIZE); |
915 | #endif | 906 | #endif |
916 | CLOSE (s); | 907 | SHUTDOWN (client_socket, SHUT_RDWR); |
908 | CLOSE (client_socket); | ||
917 | return MHD_NO; | 909 | return MHD_NO; |
918 | } | 910 | } |
919 | #endif | 911 | #endif |
@@ -932,8 +924,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
932 | MHD_DLOG (daemon, | 924 | MHD_DLOG (daemon, |
933 | "Server reached connection limit (closing inbound connection)\n"); | 925 | "Server reached connection limit (closing inbound connection)\n"); |
934 | #endif | 926 | #endif |
935 | SHUTDOWN (s, SHUT_RDWR); | 927 | SHUTDOWN (client_socket, SHUT_RDWR); |
936 | CLOSE (s); | 928 | CLOSE (client_socket); |
937 | return MHD_NO; | 929 | return MHD_NO; |
938 | } | 930 | } |
939 | 931 | ||
@@ -946,11 +938,12 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
946 | MHD_DLOG (daemon, "Connection rejected, closing connection\n"); | 938 | MHD_DLOG (daemon, "Connection rejected, closing connection\n"); |
947 | #endif | 939 | #endif |
948 | #endif | 940 | #endif |
949 | SHUTDOWN (s, SHUT_RDWR); | 941 | SHUTDOWN (client_socket, SHUT_RDWR); |
950 | CLOSE (s); | 942 | CLOSE (client_socket); |
951 | MHD_ip_limit_del (daemon, addr, addrlen); | 943 | MHD_ip_limit_del (daemon, addr, addrlen); |
952 | return MHD_YES; | 944 | return MHD_YES; |
953 | } | 945 | } |
946 | |||
954 | #if OSX | 947 | #if OSX |
955 | #ifdef SOL_SOCKET | 948 | #ifdef SOL_SOCKET |
956 | #ifdef SO_NOSIGPIPE | 949 | #ifdef SO_NOSIGPIPE |
@@ -958,14 +951,15 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
958 | #endif | 951 | #endif |
959 | #endif | 952 | #endif |
960 | #endif | 953 | #endif |
954 | |||
961 | connection = malloc (sizeof (struct MHD_Connection)); | 955 | connection = malloc (sizeof (struct MHD_Connection)); |
962 | if (NULL == connection) | 956 | if (NULL == connection) |
963 | { | 957 | { |
964 | #if HAVE_MESSAGES | 958 | #if HAVE_MESSAGES |
965 | MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); | 959 | MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); |
966 | #endif | 960 | #endif |
967 | SHUTDOWN (s, SHUT_RDWR); | 961 | SHUTDOWN (client_socket, SHUT_RDWR); |
968 | CLOSE (s); | 962 | CLOSE (client_socket); |
969 | MHD_ip_limit_del (daemon, addr, addrlen); | 963 | MHD_ip_limit_del (daemon, addr, addrlen); |
970 | return MHD_NO; | 964 | return MHD_NO; |
971 | } | 965 | } |
@@ -977,15 +971,15 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
977 | #if HAVE_MESSAGES | 971 | #if HAVE_MESSAGES |
978 | MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); | 972 | MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); |
979 | #endif | 973 | #endif |
980 | SHUTDOWN (s, SHUT_RDWR); | 974 | SHUTDOWN (client_socket, SHUT_RDWR); |
981 | CLOSE (s); | 975 | CLOSE (client_socket); |
982 | MHD_ip_limit_del (daemon, addr, addrlen); | 976 | MHD_ip_limit_del (daemon, addr, addrlen); |
983 | free (connection); | 977 | free (connection); |
984 | return MHD_NO; | 978 | return MHD_NO; |
985 | } | 979 | } |
986 | memcpy (connection->addr, addr, addrlen); | 980 | memcpy (connection->addr, addr, addrlen); |
987 | connection->addr_len = addrlen; | 981 | connection->addr_len = addrlen; |
988 | connection->socket_fd = s; | 982 | connection->socket_fd = client_socket; |
989 | connection->daemon = daemon; | 983 | connection->daemon = daemon; |
990 | connection->last_activity = time (NULL); | 984 | connection->last_activity = time (NULL); |
991 | 985 | ||
@@ -1022,8 +1016,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1022 | "Failed to setup TLS credentials: unknown credential type %d\n", | 1016 | "Failed to setup TLS credentials: unknown credential type %d\n", |
1023 | connection->daemon->cred_type); | 1017 | connection->daemon->cred_type); |
1024 | #endif | 1018 | #endif |
1025 | SHUTDOWN (s, SHUT_RDWR); | 1019 | SHUTDOWN (client_socket, SHUT_RDWR); |
1026 | CLOSE (s); | 1020 | CLOSE (client_socket); |
1027 | MHD_ip_limit_del (daemon, addr, addrlen); | 1021 | MHD_ip_limit_del (daemon, addr, addrlen); |
1028 | free (connection->addr); | 1022 | free (connection->addr); |
1029 | free (connection); | 1023 | free (connection); |
@@ -1062,8 +1056,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1062 | MHD_DLOG (daemon, "Failed to create a thread: %s\n", | 1056 | MHD_DLOG (daemon, "Failed to create a thread: %s\n", |
1063 | STRERROR (res_thread_create)); | 1057 | STRERROR (res_thread_create)); |
1064 | #endif | 1058 | #endif |
1065 | SHUTDOWN (s, SHUT_RDWR); | 1059 | SHUTDOWN (client_socket, SHUT_RDWR); |
1066 | CLOSE (s); | 1060 | CLOSE (client_socket); |
1067 | MHD_ip_limit_del (daemon, addr, addrlen); | 1061 | MHD_ip_limit_del (daemon, addr, addrlen); |
1068 | free (connection->addr); | 1062 | free (connection->addr); |
1069 | free (connection); | 1063 | free (connection); |
@@ -1073,7 +1067,55 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
1073 | connection->next = daemon->connections; | 1067 | connection->next = daemon->connections; |
1074 | daemon->connections = connection; | 1068 | daemon->connections = connection; |
1075 | daemon->max_connections--; | 1069 | daemon->max_connections--; |
1076 | return MHD_YES; | 1070 | return MHD_YES; |
1071 | } | ||
1072 | |||
1073 | |||
1074 | /** | ||
1075 | * Accept an incoming connection and create the MHD_Connection object for | ||
1076 | * it. This function also enforces policy by way of checking with the | ||
1077 | * accept policy callback. | ||
1078 | * | ||
1079 | * @param daemon handle with the listen socket | ||
1080 | * @return MHD_YES on success | ||
1081 | */ | ||
1082 | static int | ||
1083 | MHD_accept_connection (struct MHD_Daemon *daemon) | ||
1084 | { | ||
1085 | #if HAVE_INET6 | ||
1086 | struct sockaddr_in6 addrstorage; | ||
1087 | #else | ||
1088 | struct sockaddr_in addrstorage; | ||
1089 | #endif | ||
1090 | struct sockaddr *addr = (struct sockaddr *) &addrstorage; | ||
1091 | socklen_t addrlen; | ||
1092 | int s; | ||
1093 | |||
1094 | addrlen = sizeof (addrstorage); | ||
1095 | memset (addr, 0, sizeof (addrstorage)); | ||
1096 | s = ACCEPT (daemon->socket_fd, addr, &addrlen); | ||
1097 | if ((s == -1) || (addrlen <= 0)) | ||
1098 | { | ||
1099 | #if HAVE_MESSAGES | ||
1100 | /* This could be a common occurance with multiple worker threads */ | ||
1101 | if ((EAGAIN != errno) && (EWOULDBLOCK != errno)) | ||
1102 | MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); | ||
1103 | #endif | ||
1104 | if (s != -1) | ||
1105 | { | ||
1106 | SHUTDOWN (s, SHUT_RDWR); | ||
1107 | CLOSE (s); | ||
1108 | /* just in case */ | ||
1109 | } | ||
1110 | return MHD_NO; | ||
1111 | } | ||
1112 | #if HAVE_MESSAGES | ||
1113 | #if DEBUG_CONNECT | ||
1114 | MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); | ||
1115 | #endif | ||
1116 | #endif | ||
1117 | return MHD_add_connection (daemon, s, | ||
1118 | addr, addrlen); | ||
1077 | } | 1119 | } |
1078 | 1120 | ||
1079 | /** | 1121 | /** |
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h index 3f3b61de..9537c962 100644 --- a/src/include/microhttpd.h +++ b/src/include/microhttpd.h | |||
@@ -106,7 +106,7 @@ extern "C" | |||
106 | /** | 106 | /** |
107 | * Current version of the library. | 107 | * Current version of the library. |
108 | */ | 108 | */ |
109 | #define MHD_VERSION 0x00090703 | 109 | #define MHD_VERSION 0x00090800 |
110 | 110 | ||
111 | /** | 111 | /** |
112 | * MHD-internal return code for "YES". | 112 | * MHD-internal return code for "YES". |
@@ -1035,6 +1035,33 @@ void MHD_stop_daemon (struct MHD_Daemon *daemon); | |||
1035 | 1035 | ||
1036 | 1036 | ||
1037 | /** | 1037 | /** |
1038 | * Add another client connection to the set of connections | ||
1039 | * managed by MHD. This API is usually not needed (since | ||
1040 | * MHD will accept inbound connections on the server socket). | ||
1041 | * Use this API in special cases, for example if your HTTP | ||
1042 | * server is behind NAT and needs to connect out to the | ||
1043 | * HTTP client. | ||
1044 | * | ||
1045 | * The given client socket will be managed (and closed!) by MHD after | ||
1046 | * this call and must no longer be used directly by the application | ||
1047 | * afterwards. | ||
1048 | * | ||
1049 | * @param daemon daemon that manages the connection | ||
1050 | * @param client_socket socket to manage (MHD will expect | ||
1051 | * to receive an HTTP request from this socket next). | ||
1052 | * @param addr IP address of the client | ||
1053 | * @param addrlen number of bytes in addr | ||
1054 | * @return MHD_YES on success, MHD_NO if this daemon could | ||
1055 | * not handle the connection (i.e. malloc failed, etc). | ||
1056 | * The socket will be closed in any case. | ||
1057 | */ | ||
1058 | int MHD_add_connection (struct MHD_Daemon *daemon, | ||
1059 | int client_socket, | ||
1060 | const struct sockaddr *addr, | ||
1061 | socklen_t addrlen); | ||
1062 | |||
1063 | |||
1064 | /** | ||
1038 | * Obtain the select sets for this daemon. | 1065 | * Obtain the select sets for this daemon. |
1039 | * | 1066 | * |
1040 | * @param daemon daemon to get sets from | 1067 | * @param daemon daemon to get sets from |