diff options
Diffstat (limited to 'src/microhttpd')
-rw-r--r-- | src/microhttpd/Makefile.am | 2 | ||||
-rw-r--r-- | src/microhttpd/connection.c | 4 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 546 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 26 | ||||
-rw-r--r-- | src/microhttpd/mhd_locks.h | 47 | ||||
-rw-r--r-- | src/microhttpd/mhd_sem.c | 138 | ||||
-rw-r--r-- | src/microhttpd/response.c | 78 |
7 files changed, 659 insertions, 182 deletions
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am index 6973af8a..9a32f598 100644 --- a/src/microhttpd/Makefile.am +++ b/src/microhttpd/Makefile.am | |||
@@ -63,7 +63,7 @@ libmicrohttpd_la_SOURCES = \ | |||
63 | sysfdsetsize.c sysfdsetsize.h \ | 63 | sysfdsetsize.c sysfdsetsize.h \ |
64 | mhd_str.c mhd_str.h \ | 64 | mhd_str.c mhd_str.h \ |
65 | mhd_threads.c mhd_threads.h \ | 65 | mhd_threads.c mhd_threads.h \ |
66 | mhd_locks.h \ | 66 | mhd_locks.h mhd_sem.c \ |
67 | mhd_sockets.c mhd_sockets.h \ | 67 | mhd_sockets.c mhd_sockets.h \ |
68 | mhd_itc.c mhd_itc.h \ | 68 | mhd_itc.c mhd_itc.h \ |
69 | mhd_compat.c mhd_compat.h \ | 69 | mhd_compat.c mhd_compat.h \ |
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index e3880e8a..0c21bc57 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c | |||
@@ -413,7 +413,8 @@ MHD_set_connection_value (struct MHD_Connection *connection, | |||
413 | */ | 413 | */ |
414 | const char * | 414 | const char * |
415 | MHD_lookup_connection_value (struct MHD_Connection *connection, | 415 | MHD_lookup_connection_value (struct MHD_Connection *connection, |
416 | enum MHD_ValueKind kind, const char *key) | 416 | enum MHD_ValueKind kind, |
417 | const char *key) | ||
417 | { | 418 | { |
418 | struct MHD_HTTP_Header *pos; | 419 | struct MHD_HTTP_Header *pos; |
419 | 420 | ||
@@ -2772,7 +2773,6 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) | |||
2772 | /* Buffering for flushable socket was already enabled*/ | 2773 | /* Buffering for flushable socket was already enabled*/ |
2773 | if (MHD_NO == socket_flush_possible (connection)) | 2774 | if (MHD_NO == socket_flush_possible (connection)) |
2774 | socket_start_no_buffering (connection); | 2775 | socket_start_no_buffering (connection); |
2775 | |||
2776 | break; | 2776 | break; |
2777 | } | 2777 | } |
2778 | /* not ready, no socket action */ | 2778 | /* not ready, no socket action */ |
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 791e17d4..a298a1a4 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -636,6 +636,79 @@ MHD_get_fdset (struct MHD_Daemon *daemon, | |||
636 | 636 | ||
637 | 637 | ||
638 | /** | 638 | /** |
639 | * Obtain the select() file descriptor sets for the | ||
640 | * given @a urh. | ||
641 | * | ||
642 | * @param urh upgrade handle to wait for | ||
643 | * @param[out] rs read set to initialize | ||
644 | * @param[out] ws write set to initialize | ||
645 | * @param[out] max_fd maximum FD to update | ||
646 | * @param fd_setsize value of FD_SETSIZE | ||
647 | * @return #MHD_YES on success, #MHD_NO on error | ||
648 | */ | ||
649 | static int | ||
650 | urh_to_fdset (struct MHD_UpgradeResponseHandle *urh, | ||
651 | fd_set *rs, | ||
652 | fd_set *ws, | ||
653 | MHD_socket *max_fd, | ||
654 | unsigned int fd_setsize) | ||
655 | { | ||
656 | if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && | ||
657 | (! MHD_add_to_fd_set_ (urh->mhd.socket, | ||
658 | rs, | ||
659 | max_fd, | ||
660 | fd_setsize)) ) | ||
661 | return MHD_NO; | ||
662 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | ||
663 | (! MHD_add_to_fd_set_ (urh->mhd.socket, | ||
664 | ws, | ||
665 | max_fd, | ||
666 | fd_setsize)) ) | ||
667 | return MHD_NO; | ||
668 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) && | ||
669 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, | ||
670 | rs, | ||
671 | max_fd, | ||
672 | fd_setsize)) ) | ||
673 | return MHD_NO; | ||
674 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | ||
675 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, | ||
676 | ws, | ||
677 | max_fd, | ||
678 | fd_setsize)) ) | ||
679 | return MHD_NO; | ||
680 | return MHD_YES; | ||
681 | } | ||
682 | |||
683 | |||
684 | /** | ||
685 | * Update the @a urh based on the ready FDs in the @a rs and @a ws. | ||
686 | * | ||
687 | * @param urh upgrade handle to update | ||
688 | * @param rs read result from select() | ||
689 | * @param ws write result from select() | ||
690 | */ | ||
691 | static void | ||
692 | urh_from_fdset (struct MHD_UpgradeResponseHandle *urh, | ||
693 | const fd_set *rs, | ||
694 | const fd_set *ws) | ||
695 | { | ||
696 | if (FD_ISSET (urh->connection->socket_fd, | ||
697 | rs)) | ||
698 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; | ||
699 | if (FD_ISSET (urh->connection->socket_fd, | ||
700 | ws)) | ||
701 | urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
702 | if (FD_ISSET (urh->mhd.socket, | ||
703 | rs)) | ||
704 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
705 | if (FD_ISSET (urh->mhd.socket, | ||
706 | ws)) | ||
707 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
708 | } | ||
709 | |||
710 | |||
711 | /** | ||
639 | * Obtain the `select()` sets for this daemon. | 712 | * Obtain the `select()` sets for this daemon. |
640 | * Daemon's FDs will be added to fd_sets. To get only | 713 | * Daemon's FDs will be added to fd_sets. To get only |
641 | * daemon FDs in fd_sets, call FD_ZERO for each fd_set | 714 | * daemon FDs in fd_sets, call FD_ZERO for each fd_set |
@@ -733,29 +806,12 @@ MHD_get_fdset2 (struct MHD_Daemon *daemon, | |||
733 | } | 806 | } |
734 | for (urh = daemon->urh_head; NULL != urh; urh = urh->next) | 807 | for (urh = daemon->urh_head; NULL != urh; urh = urh->next) |
735 | { | 808 | { |
736 | if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && | 809 | if (MHD_NO == |
737 | (! MHD_add_to_fd_set_ (urh->mhd.socket, | 810 | urh_to_fdset (urh, |
738 | read_fd_set, | 811 | read_fd_set, |
739 | max_fd, | 812 | write_fd_set, |
740 | fd_setsize)) ) | 813 | max_fd, |
741 | result = MHD_NO; | 814 | fd_setsize)) |
742 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | ||
743 | (! MHD_add_to_fd_set_ (urh->mhd.socket, | ||
744 | write_fd_set, | ||
745 | max_fd, | ||
746 | fd_setsize)) ) | ||
747 | result = MHD_NO; | ||
748 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) && | ||
749 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, | ||
750 | read_fd_set, | ||
751 | max_fd, | ||
752 | fd_setsize)) ) | ||
753 | result = MHD_NO; | ||
754 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | ||
755 | (! MHD_add_to_fd_set_ (urh->connection->socket_fd, | ||
756 | write_fd_set, | ||
757 | max_fd, | ||
758 | fd_setsize)) ) | ||
759 | result = MHD_NO; | 815 | result = MHD_NO; |
760 | } | 816 | } |
761 | #if DEBUG_CONNECT | 817 | #if DEBUG_CONNECT |
@@ -825,6 +881,251 @@ call_handlers (struct MHD_Connection *con, | |||
825 | } | 881 | } |
826 | 882 | ||
827 | 883 | ||
884 | #if HTTPS_SUPPORT | ||
885 | /** | ||
886 | * Performs bi-directional forwarding on upgraded HTTPS connections | ||
887 | * based on the readyness state stored in the @a urh handle. | ||
888 | * | ||
889 | * @param urh handle to process | ||
890 | */ | ||
891 | static void | ||
892 | process_urh (struct MHD_UpgradeResponseHandle *urh) | ||
893 | { | ||
894 | /* handle reading from TLS client and writing to application */ | ||
895 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) && | ||
896 | (urh->in_buffer_off < urh->in_buffer_size) ) | ||
897 | { | ||
898 | ssize_t res; | ||
899 | |||
900 | res = gnutls_record_recv (urh->connection->tls_session, | ||
901 | &urh->in_buffer[urh->in_buffer_off], | ||
902 | urh->in_buffer_size - urh->in_buffer_off); | ||
903 | if ( (GNUTLS_E_AGAIN == res) || | ||
904 | (GNUTLS_E_INTERRUPTED == res) ) | ||
905 | { | ||
906 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
907 | } | ||
908 | else if (res > 0) | ||
909 | { | ||
910 | urh->in_buffer_off += res; | ||
911 | } | ||
912 | } | ||
913 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | ||
914 | (urh->in_buffer_off > 0) ) | ||
915 | { | ||
916 | size_t res; | ||
917 | |||
918 | res = write (urh->mhd.socket, | ||
919 | urh->in_buffer, | ||
920 | urh->in_buffer_off); | ||
921 | if (-1 == res) | ||
922 | { | ||
923 | /* FIXME: differenciate by errno? */ | ||
924 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
925 | } | ||
926 | else | ||
927 | { | ||
928 | if (urh->in_buffer_off != res) | ||
929 | { | ||
930 | memmove (urh->in_buffer, | ||
931 | &urh->in_buffer[res], | ||
932 | urh->in_buffer_off - res); | ||
933 | urh->in_buffer_off -= res; | ||
934 | } | ||
935 | else | ||
936 | { | ||
937 | urh->in_buffer_off = 0; | ||
938 | } | ||
939 | } | ||
940 | } | ||
941 | |||
942 | /* handle reading from application and writing to HTTPS client */ | ||
943 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && | ||
944 | (urh->out_buffer_off < urh->out_buffer_size) ) | ||
945 | { | ||
946 | size_t res; | ||
947 | |||
948 | res = read (urh->mhd.socket, | ||
949 | &urh->out_buffer[urh->out_buffer_off], | ||
950 | urh->out_buffer_size - urh->out_buffer_off); | ||
951 | if (-1 == res) | ||
952 | { | ||
953 | /* FIXME: differenciate by errno? */ | ||
954 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
955 | } | ||
956 | else | ||
957 | { | ||
958 | urh->out_buffer_off += res; | ||
959 | } | ||
960 | } | ||
961 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | ||
962 | (urh->out_buffer_off > 0) ) | ||
963 | { | ||
964 | ssize_t res; | ||
965 | |||
966 | res = gnutls_record_send (urh->connection->tls_session, | ||
967 | urh->out_buffer, | ||
968 | urh->out_buffer_off); | ||
969 | if ( (GNUTLS_E_AGAIN == res) || | ||
970 | (GNUTLS_E_INTERRUPTED == res) ) | ||
971 | { | ||
972 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
973 | } | ||
974 | else if (res > 0) | ||
975 | { | ||
976 | if (urh->out_buffer_off != res) | ||
977 | { | ||
978 | memmove (urh->out_buffer, | ||
979 | &urh->out_buffer[res], | ||
980 | urh->out_buffer_off - res); | ||
981 | urh->out_buffer_off -= res; | ||
982 | } | ||
983 | else | ||
984 | { | ||
985 | urh->out_buffer_off = 0; | ||
986 | } | ||
987 | } | ||
988 | } | ||
989 | } | ||
990 | #endif | ||
991 | |||
992 | |||
993 | /** | ||
994 | * Main function of the thread that handles an individual connection | ||
995 | * after it was "upgraded" when #MHD_USE_THREAD_PER_CONNECTION is set. | ||
996 | * | ||
997 | * @param con the connection this thread will handle | ||
998 | */ | ||
999 | static void | ||
1000 | thread_main_connection_upgrade (struct MHD_Connection *con) | ||
1001 | { | ||
1002 | struct MHD_Daemon *daemon = con->daemon; | ||
1003 | |||
1004 | if (0 == (daemon->options & MHD_USE_SSL)) | ||
1005 | { | ||
1006 | /* Here, we need to block until the application | ||
1007 | signals us that it is done with the socket */ | ||
1008 | MHD_semaphore_down (con->upgrade_sem); | ||
1009 | MHD_semaphore_destroy (con->upgrade_sem); | ||
1010 | con->upgrade_sem = NULL; | ||
1011 | return; | ||
1012 | } | ||
1013 | #if HTTPS_SUPPORT | ||
1014 | { | ||
1015 | struct MHD_UpgradeResponseHandle *urh = con->urh; | ||
1016 | |||
1017 | /* Here, we need to bi-directionally forward | ||
1018 | until the application tells us that it is done | ||
1019 | with the socket; */ | ||
1020 | if (0 == (daemon->options & MHD_USE_POLL)) | ||
1021 | { | ||
1022 | while (MHD_CONNECTION_UPGRADE == con->state) | ||
1023 | { | ||
1024 | /* use select */ | ||
1025 | fd_set rs; | ||
1026 | fd_set ws; | ||
1027 | MHD_socket max_fd; | ||
1028 | int num_ready; | ||
1029 | int result; | ||
1030 | |||
1031 | FD_ZERO (&rs); | ||
1032 | FD_ZERO (&ws); | ||
1033 | max_fd = MHD_INVALID_SOCKET; | ||
1034 | result = urh_to_fdset (urh, | ||
1035 | &rs, | ||
1036 | &ws, | ||
1037 | &max_fd, | ||
1038 | FD_SETSIZE); | ||
1039 | if (MHD_NO == result) | ||
1040 | { | ||
1041 | #ifdef HAVE_MESSAGES | ||
1042 | MHD_DLOG (con->daemon, | ||
1043 | "Error preparing select\n"); | ||
1044 | #endif | ||
1045 | break; | ||
1046 | } | ||
1047 | num_ready = MHD_SYS_select_ (max_fd + 1, | ||
1048 | &rs, | ||
1049 | &ws, | ||
1050 | NULL, | ||
1051 | NULL); | ||
1052 | if (num_ready < 0) | ||
1053 | { | ||
1054 | const int err = MHD_socket_get_error_(); | ||
1055 | |||
1056 | if (MHD_SCKT_ERR_IS_EINTR_(err)) | ||
1057 | continue; | ||
1058 | #ifdef HAVE_MESSAGES | ||
1059 | MHD_DLOG (con->daemon, | ||
1060 | "Error during select (%d): `%s'\n", | ||
1061 | err, | ||
1062 | MHD_socket_strerr_ (err)); | ||
1063 | #endif | ||
1064 | break; | ||
1065 | } | ||
1066 | urh_from_fdset (urh, | ||
1067 | &rs, | ||
1068 | &ws); | ||
1069 | process_urh (urh); | ||
1070 | } | ||
1071 | } | ||
1072 | #ifdef HAVE_POLL | ||
1073 | else | ||
1074 | { | ||
1075 | /* use poll() */ | ||
1076 | struct pollfd p[2]; | ||
1077 | const unsigned int timeout = UINT_MAX; | ||
1078 | |||
1079 | p[0].fd = urh->connection->socket_fd; | ||
1080 | p[1].fd = urh->mhd.socket; | ||
1081 | while (MHD_CONNECTION_UPGRADE == con->state) | ||
1082 | { | ||
1083 | if (0 == (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) | ||
1084 | p[0].events |= POLLIN; | ||
1085 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) | ||
1086 | p[0].events |= POLLOUT; | ||
1087 | if (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) | ||
1088 | p[1].events |= POLLIN; | ||
1089 | if (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) | ||
1090 | p[1].events |= POLLOUT; | ||
1091 | |||
1092 | if (MHD_sys_poll_ (p, | ||
1093 | 2, | ||
1094 | timeout) < 0) | ||
1095 | { | ||
1096 | const int err = MHD_socket_get_error_ (); | ||
1097 | |||
1098 | if (MHD_SCKT_ERR_IS_EINTR_ (err)) | ||
1099 | continue; | ||
1100 | #ifdef HAVE_MESSAGES | ||
1101 | MHD_DLOG (con->daemon, | ||
1102 | "Error during poll: `%s'\n", | ||
1103 | MHD_socket_strerr_ (err)); | ||
1104 | #endif | ||
1105 | break; | ||
1106 | } | ||
1107 | if (0 != (p[0].revents & POLLIN)) | ||
1108 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; | ||
1109 | if (0 != (p[0].revents & POLLOUT)) | ||
1110 | urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
1111 | if (0 != (p[1].revents & POLLIN)) | ||
1112 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
1113 | if (0 != (p[1].revents & POLLOUT)) | ||
1114 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
1115 | process_urh (urh); | ||
1116 | } | ||
1117 | } | ||
1118 | /* end POLL */ | ||
1119 | #endif | ||
1120 | /* end HTTPS */ | ||
1121 | #else | ||
1122 | /* HTTPS option set, but compiled without HTTPS */ | ||
1123 | MHD_PANIC ("This should not be possible\n"); | ||
1124 | #endif | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | |||
828 | /** | 1129 | /** |
829 | * Main function of the thread that handles an individual | 1130 | * Main function of the thread that handles an individual |
830 | * connection when #MHD_USE_THREAD_PER_CONNECTION is set. | 1131 | * connection when #MHD_USE_THREAD_PER_CONNECTION is set. |
@@ -836,6 +1137,7 @@ static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ | |||
836 | thread_main_handle_connection (void *data) | 1137 | thread_main_handle_connection (void *data) |
837 | { | 1138 | { |
838 | struct MHD_Connection *con = data; | 1139 | struct MHD_Connection *con = data; |
1140 | struct MHD_Daemon *daemon = con->daemon; | ||
839 | int num_ready; | 1141 | int num_ready; |
840 | fd_set rs; | 1142 | fd_set rs; |
841 | fd_set ws; | 1143 | fd_set ws; |
@@ -844,7 +1146,7 @@ thread_main_handle_connection (void *data) | |||
844 | struct timeval *tvp; | 1146 | struct timeval *tvp; |
845 | time_t now; | 1147 | time_t now; |
846 | #if WINDOWS | 1148 | #if WINDOWS |
847 | MHD_pipe spipe = con->daemon->wpipe[0]; | 1149 | MHD_pipe spipe = daemon->wpipe[0]; |
848 | #ifdef HAVE_POLL | 1150 | #ifdef HAVE_POLL |
849 | int extra_slot; | 1151 | int extra_slot; |
850 | #endif /* HAVE_POLL */ | 1152 | #endif /* HAVE_POLL */ |
@@ -855,11 +1157,13 @@ thread_main_handle_connection (void *data) | |||
855 | #ifdef HAVE_POLL | 1157 | #ifdef HAVE_POLL |
856 | struct pollfd p[1 + EXTRA_SLOTS]; | 1158 | struct pollfd p[1 + EXTRA_SLOTS]; |
857 | #endif | 1159 | #endif |
1160 | #undef EXTRA_SLOTS | ||
858 | 1161 | ||
859 | while ( (MHD_YES != con->daemon->shutdown) && | 1162 | while ( (MHD_YES != daemon->shutdown) && |
860 | (MHD_CONNECTION_CLOSED != con->state) ) | 1163 | (MHD_CONNECTION_CLOSED != con->state) ) |
861 | { | 1164 | { |
862 | unsigned const int timeout = con->daemon->connection_timeout; | 1165 | const unsigned int timeout = daemon->connection_timeout; |
1166 | |||
863 | tvp = NULL; | 1167 | tvp = NULL; |
864 | #if HTTPS_SUPPORT | 1168 | #if HTTPS_SUPPORT |
865 | if (MHD_YES == con->tls_read_ready) | 1169 | if (MHD_YES == con->tls_read_ready) |
@@ -870,7 +1174,8 @@ thread_main_handle_connection (void *data) | |||
870 | tvp = &tv; | 1174 | tvp = &tv; |
871 | } | 1175 | } |
872 | #endif | 1176 | #endif |
873 | if (NULL == tvp && timeout > 0) | 1177 | if ( (NULL == tvp) && |
1178 | (timeout > 0) ) | ||
874 | { | 1179 | { |
875 | now = MHD_monotonic_sec_counter(); | 1180 | now = MHD_monotonic_sec_counter(); |
876 | if (now - con->last_activity > timeout) | 1181 | if (now - con->last_activity > timeout) |
@@ -884,35 +1189,48 @@ thread_main_handle_connection (void *data) | |||
884 | if (seconds_left > TIMEVAL_TV_SEC_MAX) | 1189 | if (seconds_left > TIMEVAL_TV_SEC_MAX) |
885 | tv.tv_sec = TIMEVAL_TV_SEC_MAX; | 1190 | tv.tv_sec = TIMEVAL_TV_SEC_MAX; |
886 | else | 1191 | else |
887 | tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE)seconds_left; | 1192 | tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) seconds_left; |
888 | #endif /* _WIN32 */ | 1193 | #endif /* _WIN32 */ |
889 | } | 1194 | } |
890 | tv.tv_usec = 0; | 1195 | tv.tv_usec = 0; |
891 | tvp = &tv; | 1196 | tvp = &tv; |
892 | } | 1197 | } |
893 | if (0 == (con->daemon->options & MHD_USE_POLL)) | 1198 | if (0 == (daemon->options & MHD_USE_POLL)) |
894 | { | 1199 | { |
895 | /* use select */ | 1200 | /* use select */ |
896 | int err_state = 0; | 1201 | int err_state = 0; |
1202 | |||
897 | FD_ZERO (&rs); | 1203 | FD_ZERO (&rs); |
898 | FD_ZERO (&ws); | 1204 | FD_ZERO (&ws); |
899 | maxsock = MHD_INVALID_SOCKET; | 1205 | maxsock = MHD_INVALID_SOCKET; |
900 | switch (con->event_loop_info) | 1206 | switch (con->event_loop_info) |
901 | { | 1207 | { |
902 | case MHD_EVENT_LOOP_INFO_READ: | 1208 | case MHD_EVENT_LOOP_INFO_READ: |
903 | if (!MHD_add_to_fd_set_ (con->socket_fd, &rs, &maxsock, FD_SETSIZE)) | 1209 | if (! MHD_add_to_fd_set_ (con->socket_fd, |
1210 | &rs, | ||
1211 | &maxsock, | ||
1212 | FD_SETSIZE)) | ||
904 | err_state = 1; | 1213 | err_state = 1; |
905 | break; | 1214 | break; |
906 | case MHD_EVENT_LOOP_INFO_WRITE: | 1215 | case MHD_EVENT_LOOP_INFO_WRITE: |
907 | if (!MHD_add_to_fd_set_ (con->socket_fd, &ws, &maxsock, FD_SETSIZE)) | 1216 | if (! MHD_add_to_fd_set_ (con->socket_fd, |
1217 | &ws, | ||
1218 | &maxsock, | ||
1219 | FD_SETSIZE)) | ||
908 | err_state = 1; | 1220 | err_state = 1; |
909 | if ( (con->read_buffer_size > con->read_buffer_offset) && | 1221 | if ( (con->read_buffer_size > con->read_buffer_offset) && |
910 | (!MHD_add_to_fd_set_ (con->socket_fd, &rs, &maxsock, FD_SETSIZE)) ) | 1222 | (! MHD_add_to_fd_set_ (con->socket_fd, |
1223 | &rs, | ||
1224 | &maxsock, | ||
1225 | FD_SETSIZE)) ) | ||
911 | err_state = 1; | 1226 | err_state = 1; |
912 | break; | 1227 | break; |
913 | case MHD_EVENT_LOOP_INFO_BLOCK: | 1228 | case MHD_EVENT_LOOP_INFO_BLOCK: |
914 | if ( (con->read_buffer_size > con->read_buffer_offset) && | 1229 | if ( (con->read_buffer_size > con->read_buffer_offset) && |
915 | (!MHD_add_to_fd_set_ (con->socket_fd, &rs, &maxsock, FD_SETSIZE)) ) | 1230 | (! MHD_add_to_fd_set_ (con->socket_fd, |
1231 | &rs, | ||
1232 | &maxsock, | ||
1233 | FD_SETSIZE)) ) | ||
916 | err_state = 1; | 1234 | err_state = 1; |
917 | tv.tv_sec = 0; | 1235 | tv.tv_sec = 0; |
918 | tv.tv_usec = 0; | 1236 | tv.tv_usec = 0; |
@@ -925,7 +1243,10 @@ thread_main_handle_connection (void *data) | |||
925 | #if WINDOWS | 1243 | #if WINDOWS |
926 | if (MHD_INVALID_PIPE_ != spipe) | 1244 | if (MHD_INVALID_PIPE_ != spipe) |
927 | { | 1245 | { |
928 | if (!MHD_add_to_fd_set_ (spipe, &rs, &maxsock, FD_SETSIZE)) | 1246 | if (! MHD_add_to_fd_set_ (spipe, |
1247 | &rs, | ||
1248 | &maxsock, | ||
1249 | FD_SETSIZE)) | ||
929 | err_state = 1; | 1250 | err_state = 1; |
930 | } | 1251 | } |
931 | #endif | 1252 | #endif |
@@ -938,10 +1259,15 @@ thread_main_handle_connection (void *data) | |||
938 | goto exit; | 1259 | goto exit; |
939 | } | 1260 | } |
940 | 1261 | ||
941 | num_ready = MHD_SYS_select_ (maxsock + 1, &rs, &ws, NULL, tvp); | 1262 | num_ready = MHD_SYS_select_ (maxsock + 1, |
1263 | &rs, | ||
1264 | &ws, | ||
1265 | NULL, | ||
1266 | tvp); | ||
942 | if (num_ready < 0) | 1267 | if (num_ready < 0) |
943 | { | 1268 | { |
944 | const int err = MHD_socket_get_error_(); | 1269 | const int err = MHD_socket_get_error_(); |
1270 | |||
945 | if (MHD_SCKT_ERR_IS_EINTR_(err)) | 1271 | if (MHD_SCKT_ERR_IS_EINTR_(err)) |
946 | continue; | 1272 | continue; |
947 | #ifdef HAVE_MESSAGES | 1273 | #ifdef HAVE_MESSAGES |
@@ -960,8 +1286,10 @@ thread_main_handle_connection (void *data) | |||
960 | #endif | 1286 | #endif |
961 | if (MHD_NO == | 1287 | if (MHD_NO == |
962 | call_handlers (con, | 1288 | call_handlers (con, |
963 | FD_ISSET (con->socket_fd, &rs), | 1289 | FD_ISSET (con->socket_fd, |
964 | FD_ISSET (con->socket_fd, &ws), | 1290 | &rs), |
1291 | FD_ISSET (con->socket_fd, | ||
1292 | &ws), | ||
965 | MHD_NO)) | 1293 | MHD_NO)) |
966 | goto exit; | 1294 | goto exit; |
967 | } | 1295 | } |
@@ -969,7 +1297,9 @@ thread_main_handle_connection (void *data) | |||
969 | else | 1297 | else |
970 | { | 1298 | { |
971 | /* use poll */ | 1299 | /* use poll */ |
972 | memset (&p, 0, sizeof (p)); | 1300 | memset (&p, |
1301 | 0, | ||
1302 | sizeof (p)); | ||
973 | p[0].fd = con->socket_fd; | 1303 | p[0].fd = con->socket_fd; |
974 | switch (con->event_loop_info) | 1304 | switch (con->event_loop_info) |
975 | { | 1305 | { |
@@ -1004,11 +1334,11 @@ thread_main_handle_connection (void *data) | |||
1004 | #endif | 1334 | #endif |
1005 | if (MHD_sys_poll_ (p, | 1335 | if (MHD_sys_poll_ (p, |
1006 | #if WINDOWS | 1336 | #if WINDOWS |
1007 | 1 + extra_slot, | 1337 | 1 + extra_slot, |
1008 | #else | 1338 | #else |
1009 | 1, | 1339 | 1, |
1010 | #endif | 1340 | #endif |
1011 | (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0) | 1341 | (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0) |
1012 | { | 1342 | { |
1013 | if (MHD_SCKT_LAST_ERR_IS_(MHD_SCKT_EINTR_)) | 1343 | if (MHD_SCKT_LAST_ERR_IS_(MHD_SCKT_EINTR_)) |
1014 | continue; | 1344 | continue; |
@@ -1033,6 +1363,11 @@ thread_main_handle_connection (void *data) | |||
1033 | goto exit; | 1363 | goto exit; |
1034 | } | 1364 | } |
1035 | #endif | 1365 | #endif |
1366 | if (MHD_CONNECTION_UPGRADE == con->state) | ||
1367 | { | ||
1368 | thread_main_connection_upgrade (con); | ||
1369 | break; | ||
1370 | } | ||
1036 | } | 1371 | } |
1037 | if (MHD_CONNECTION_IN_CLEANUP != con->state) | 1372 | if (MHD_CONNECTION_IN_CLEANUP != con->state) |
1038 | { | 1373 | { |
@@ -1054,14 +1389,15 @@ exit: | |||
1054 | con->response = NULL; | 1389 | con->response = NULL; |
1055 | } | 1390 | } |
1056 | 1391 | ||
1057 | if (NULL != con->daemon->notify_connection) | 1392 | if (NULL != daemon->notify_connection) |
1058 | con->daemon->notify_connection (con->daemon->notify_connection_cls, | 1393 | con->daemon->notify_connection (daemon->notify_connection_cls, |
1059 | con, | 1394 | con, |
1060 | &con->socket_context, | 1395 | &con->socket_context, |
1061 | MHD_CONNECTION_NOTIFY_CLOSED); | 1396 | MHD_CONNECTION_NOTIFY_CLOSED); |
1062 | if (MHD_INVALID_SOCKET != con->socket_fd) | 1397 | if (MHD_INVALID_SOCKET != con->socket_fd) |
1063 | { | 1398 | { |
1064 | shutdown (con->socket_fd, SHUT_WR); | 1399 | shutdown (con->socket_fd, |
1400 | SHUT_WR); | ||
1065 | if (0 != MHD_socket_close_ (con->socket_fd)) | 1401 | if (0 != MHD_socket_close_ (con->socket_fd)) |
1066 | MHD_PANIC ("close failed\n"); | 1402 | MHD_PANIC ("close failed\n"); |
1067 | con->socket_fd = MHD_INVALID_SOCKET; | 1403 | con->socket_fd = MHD_INVALID_SOCKET; |
@@ -1433,7 +1769,7 @@ internal_add_connection (struct MHD_Daemon *daemon, | |||
1433 | { | 1769 | { |
1434 | /* in turbo mode, we assume that non-blocking was already set | 1770 | /* in turbo mode, we assume that non-blocking was already set |
1435 | by 'accept4' or whoever calls 'MHD_add_connection' */ | 1771 | by 'accept4' or whoever calls 'MHD_add_connection' */ |
1436 | if (!MHD_socket_nonblocking_ (connection->socket_fd)) | 1772 | if (! MHD_socket_nonblocking_ (connection->socket_fd)) |
1437 | { | 1773 | { |
1438 | #ifdef HAVE_MESSAGES | 1774 | #ifdef HAVE_MESSAGES |
1439 | MHD_DLOG (connection->daemon, | 1775 | MHD_DLOG (connection->daemon, |
@@ -2168,115 +2504,6 @@ MHD_get_timeout (struct MHD_Daemon *daemon, | |||
2168 | } | 2504 | } |
2169 | 2505 | ||
2170 | 2506 | ||
2171 | #if HTTPS_SUPPORT | ||
2172 | /** | ||
2173 | * Performs bi-directional forwarding on upgraded HTTPS connections | ||
2174 | * based on the readyness state stored in the @a urh handle. | ||
2175 | * | ||
2176 | * @param urh handle to process | ||
2177 | */ | ||
2178 | static void | ||
2179 | process_urh (struct MHD_UpgradeResponseHandle *urh) | ||
2180 | { | ||
2181 | /* handle reading from TLS client and writing to application */ | ||
2182 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) && | ||
2183 | (urh->in_buffer_off < urh->in_buffer_size) ) | ||
2184 | { | ||
2185 | ssize_t res; | ||
2186 | |||
2187 | res = gnutls_record_recv (urh->connection->tls_session, | ||
2188 | &urh->in_buffer[urh->in_buffer_off], | ||
2189 | urh->in_buffer_size - urh->in_buffer_off); | ||
2190 | if ( (GNUTLS_E_AGAIN == res) || | ||
2191 | (GNUTLS_E_INTERRUPTED == res) ) | ||
2192 | { | ||
2193 | urh->app.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
2194 | } | ||
2195 | else if (res > 0) | ||
2196 | { | ||
2197 | urh->in_buffer_off += res; | ||
2198 | } | ||
2199 | } | ||
2200 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) && | ||
2201 | (urh->in_buffer_off > 0) ) | ||
2202 | { | ||
2203 | size_t res; | ||
2204 | |||
2205 | res = write (urh->mhd.socket, | ||
2206 | urh->in_buffer, | ||
2207 | urh->in_buffer_off); | ||
2208 | if (-1 == res) | ||
2209 | { | ||
2210 | /* FIXME: differenciate by errno? */ | ||
2211 | urh->mhd.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
2212 | } | ||
2213 | else | ||
2214 | { | ||
2215 | if (urh->in_buffer_off != res) | ||
2216 | { | ||
2217 | memmove (urh->in_buffer, | ||
2218 | &urh->in_buffer[res], | ||
2219 | urh->in_buffer_off - res); | ||
2220 | urh->in_buffer_off -= res; | ||
2221 | } | ||
2222 | else | ||
2223 | { | ||
2224 | urh->in_buffer_off = 0; | ||
2225 | } | ||
2226 | } | ||
2227 | } | ||
2228 | |||
2229 | /* handle reading from application and writing to HTTPS client */ | ||
2230 | if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) && | ||
2231 | (urh->out_buffer_off < urh->out_buffer_size) ) | ||
2232 | { | ||
2233 | size_t res; | ||
2234 | |||
2235 | res = read (urh->mhd.socket, | ||
2236 | &urh->out_buffer[urh->out_buffer_off], | ||
2237 | urh->out_buffer_size - urh->out_buffer_off); | ||
2238 | if (-1 == res) | ||
2239 | { | ||
2240 | /* FIXME: differenciate by errno? */ | ||
2241 | urh->mhd.celi &= ~MHD_EPOLL_STATE_READ_READY; | ||
2242 | } | ||
2243 | else | ||
2244 | { | ||
2245 | urh->out_buffer_off += res; | ||
2246 | } | ||
2247 | } | ||
2248 | if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) && | ||
2249 | (urh->out_buffer_off > 0) ) | ||
2250 | { | ||
2251 | ssize_t res; | ||
2252 | |||
2253 | res = gnutls_record_send (urh->connection->tls_session, | ||
2254 | urh->out_buffer, | ||
2255 | urh->out_buffer_off); | ||
2256 | if ( (GNUTLS_E_AGAIN == res) || | ||
2257 | (GNUTLS_E_INTERRUPTED == res) ) | ||
2258 | { | ||
2259 | urh->app.celi &= ~MHD_EPOLL_STATE_WRITE_READY; | ||
2260 | } | ||
2261 | else if (res > 0) | ||
2262 | { | ||
2263 | if (urh->out_buffer_off != res) | ||
2264 | { | ||
2265 | memmove (urh->out_buffer, | ||
2266 | &urh->out_buffer[res], | ||
2267 | urh->out_buffer_off - res); | ||
2268 | urh->out_buffer_off -= res; | ||
2269 | } | ||
2270 | else | ||
2271 | { | ||
2272 | urh->out_buffer_off = 0; | ||
2273 | } | ||
2274 | } | ||
2275 | } | ||
2276 | } | ||
2277 | #endif | ||
2278 | |||
2279 | |||
2280 | /** | 2507 | /** |
2281 | * Run webserver operations. This method should be called by clients | 2508 | * Run webserver operations. This method should be called by clients |
2282 | * in combination with #MHD_get_fdset if the client-controlled select | 2509 | * in combination with #MHD_get_fdset if the client-controlled select |
@@ -2362,14 +2589,9 @@ MHD_run_from_select (struct MHD_Daemon *daemon, | |||
2362 | for (urh = daemon->urh_head; NULL != urh; urh = urh->next) | 2589 | for (urh = daemon->urh_head; NULL != urh; urh = urh->next) |
2363 | { | 2590 | { |
2364 | /* update urh state based on select() output */ | 2591 | /* update urh state based on select() output */ |
2365 | if (FD_ISSET (urh->connection->socket_fd, read_fd_set)) | 2592 | urh_from_fdset (urh, |
2366 | urh->app.celi |= MHD_EPOLL_STATE_READ_READY; | 2593 | read_fd_set, |
2367 | if (FD_ISSET (urh->connection->socket_fd, write_fd_set)) | 2594 | write_fd_set); |
2368 | urh->app.celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
2369 | if (FD_ISSET (urh->mhd.socket, read_fd_set)) | ||
2370 | urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY; | ||
2371 | if (FD_ISSET (urh->mhd.socket, write_fd_set)) | ||
2372 | urh->mhd.celi |= MHD_EPOLL_STATE_WRITE_READY; | ||
2373 | /* call generic forwarding function for passing data */ | 2595 | /* call generic forwarding function for passing data */ |
2374 | process_urh (urh); | 2596 | process_urh (urh); |
2375 | } | 2597 | } |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index 00843729..7a1e58e1 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -480,7 +480,14 @@ enum MHD_CONNECTION_STATE | |||
480 | * Connection was "upgraded" and socket is now under the | 480 | * Connection was "upgraded" and socket is now under the |
481 | * control of the application. | 481 | * control of the application. |
482 | */ | 482 | */ |
483 | MHD_CONNECTION_UPGRADE = MHD_TLS_CONNECTION_INIT + 1 | 483 | MHD_CONNECTION_UPGRADE = MHD_TLS_CONNECTION_INIT + 1, |
484 | |||
485 | /** | ||
486 | * Connection was "upgraded" and subsequently closed | ||
487 | * by the application. We now need to do our own | ||
488 | * internal cleanup. | ||
489 | */ | ||
490 | MHD_CONNECTION_UPGRADE_CLOSED = MHD_TLS_CONNECTION_INIT + 1 | ||
484 | 491 | ||
485 | }; | 492 | }; |
486 | 493 | ||
@@ -854,6 +861,23 @@ struct MHD_Connection | |||
854 | 861 | ||
855 | #if HTTPS_SUPPORT | 862 | #if HTTPS_SUPPORT |
856 | /** | 863 | /** |
864 | * If this connection was upgraded and if we are using | ||
865 | * #MHD_USE_THREAD_PER_CONNECTION, this points to the | ||
866 | * upgrade response details such that the | ||
867 | * #thread_main_connection_upgrade()-logic can perform | ||
868 | * the bi-directional forwarding. | ||
869 | */ | ||
870 | struct MHD_UpgradeResponseHandle *urh; | ||
871 | |||
872 | /** | ||
873 | * If this connection was upgraded and if we are using | ||
874 | * #MHD_USE_THREAD_PER_CONNECTION without encryption, | ||
875 | * this points to the semaphore we use to signal termination | ||
876 | * to the thread handling the connection. | ||
877 | */ | ||
878 | struct MHD_Semaphore *upgrade_sem; | ||
879 | |||
880 | /** | ||
857 | * State required for HTTPS/SSL/TLS support. | 881 | * State required for HTTPS/SSL/TLS support. |
858 | */ | 882 | */ |
859 | gnutls_session_t tls_session; | 883 | gnutls_session_t tls_session; |
diff --git a/src/microhttpd/mhd_locks.h b/src/microhttpd/mhd_locks.h index cf10c0d1..1d8376f0 100644 --- a/src/microhttpd/mhd_locks.h +++ b/src/microhttpd/mhd_locks.h | |||
@@ -22,8 +22,9 @@ | |||
22 | * @file microhttpd/mhd_locks.h | 22 | * @file microhttpd/mhd_locks.h |
23 | * @brief Header for platform-independent locks abstraction | 23 | * @brief Header for platform-independent locks abstraction |
24 | * @author Karlson2k (Evgeny Grin) | 24 | * @author Karlson2k (Evgeny Grin) |
25 | * @author Christian Grothoff | ||
25 | * | 26 | * |
26 | * Provides basic abstraction for locks and mutex. | 27 | * Provides basic abstraction for locks/mutex and semaphores. |
27 | * Any functions can be implemented as macro on some platforms | 28 | * Any functions can be implemented as macro on some platforms |
28 | * unless explicitly marked otherwise. | 29 | * unless explicitly marked otherwise. |
29 | * Any function argument can be skipped in macro, so avoid | 30 | * Any function argument can be skipped in macro, so avoid |
@@ -147,4 +148,48 @@ | |||
147 | #define MHD_mutex_unlock_(pmutex) (LeaveCriticalSection((pmutex)), !0) | 148 | #define MHD_mutex_unlock_(pmutex) (LeaveCriticalSection((pmutex)), !0) |
148 | #endif | 149 | #endif |
149 | 150 | ||
151 | |||
152 | /** | ||
153 | * A semaphore. | ||
154 | */ | ||
155 | struct MHD_Semaphore; | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Create a semaphore with an initial counter of @a init | ||
160 | * | ||
161 | * @param init initial counter | ||
162 | * @return the semaphore, NULL on error | ||
163 | */ | ||
164 | struct MHD_Semaphore * | ||
165 | MHD_semaphore_create (unsigned int init); | ||
166 | |||
167 | |||
168 | /** | ||
169 | * Count down the semaphore, block if necessary. | ||
170 | * | ||
171 | * @param sem semaphore to count down. | ||
172 | */ | ||
173 | void | ||
174 | MHD_semaphore_down (struct MHD_Semaphore *sem); | ||
175 | |||
176 | |||
177 | /** | ||
178 | * Increment the semaphore. | ||
179 | * | ||
180 | * @param sem semaphore to increment. | ||
181 | */ | ||
182 | void | ||
183 | MHD_semaphore_up (struct MHD_Semaphore *sem); | ||
184 | |||
185 | |||
186 | /** | ||
187 | * Destroys the semaphore. | ||
188 | * | ||
189 | * @param sem semaphore to destroy. | ||
190 | */ | ||
191 | void | ||
192 | MHD_semaphore_destroy (struct MHD_Semaphore *sem); | ||
193 | |||
194 | |||
150 | #endif /* ! MHD_LOCKS_H */ | 195 | #endif /* ! MHD_LOCKS_H */ |
diff --git a/src/microhttpd/mhd_sem.c b/src/microhttpd/mhd_sem.c new file mode 100644 index 00000000..fdd5dbe4 --- /dev/null +++ b/src/microhttpd/mhd_sem.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2016 Christian Grothoff | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file microhttpd/mhd_sem.c | ||
23 | * @brief implementation of semaphores | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "internal.h" | ||
27 | #include "mhd_locks.h" | ||
28 | |||
29 | /** | ||
30 | * A semaphore. | ||
31 | */ | ||
32 | struct MHD_Semaphore | ||
33 | { | ||
34 | /** | ||
35 | * Mutex we use internally. | ||
36 | */ | ||
37 | pthread_mutex_t mutex; | ||
38 | |||
39 | /** | ||
40 | * Condition variable used to implement the semaphore. | ||
41 | */ | ||
42 | pthread_cond_t cv; | ||
43 | |||
44 | /** | ||
45 | * Current value of the semaphore. | ||
46 | */ | ||
47 | unsigned int counter; | ||
48 | }; | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Create a semaphore with an initial counter of @a init | ||
53 | * | ||
54 | * @param init initial counter | ||
55 | * @return the semaphore, NULL on error | ||
56 | */ | ||
57 | struct MHD_Semaphore * | ||
58 | MHD_semaphore_create (unsigned int init) | ||
59 | { | ||
60 | struct MHD_Semaphore *sem; | ||
61 | |||
62 | sem = malloc (sizeof (struct MHD_Semaphore)); | ||
63 | if (NULL == sem) | ||
64 | return NULL; | ||
65 | sem->counter = init; | ||
66 | if (0 != pthread_mutex_init (&sem->mutex, | ||
67 | NULL)) | ||
68 | { | ||
69 | free (sem); | ||
70 | return NULL; | ||
71 | } | ||
72 | if (0 != pthread_cond_init (&sem->cv, | ||
73 | NULL)) | ||
74 | { | ||
75 | (void) pthread_mutex_destroy (&sem->mutex); | ||
76 | free (sem); | ||
77 | return NULL; | ||
78 | } | ||
79 | return sem; | ||
80 | } | ||
81 | |||
82 | |||
83 | /** | ||
84 | * Count down the semaphore, block if necessary. | ||
85 | * | ||
86 | * @param sem semaphore to count down. | ||
87 | */ | ||
88 | void | ||
89 | MHD_semaphore_down (struct MHD_Semaphore *sem) | ||
90 | { | ||
91 | if (! pthread_mutex_lock (&sem->mutex)) | ||
92 | MHD_PANIC ("pthread_mutex_lock for semaphore failed\n"); | ||
93 | while (0 == sem->counter) | ||
94 | { | ||
95 | if (0 != pthread_cond_wait (&sem->cv, | ||
96 | &sem->mutex)) | ||
97 | MHD_PANIC ("pthread_cond_wait failed\n"); | ||
98 | } | ||
99 | sem->counter--; | ||
100 | if (! pthread_mutex_unlock (&sem->mutex)) | ||
101 | MHD_PANIC ("pthread_mutex_unlock for semaphore failed\n"); | ||
102 | } | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Increment the semaphore. | ||
107 | * | ||
108 | * @param sem semaphore to increment. | ||
109 | */ | ||
110 | void | ||
111 | MHD_semaphore_up (struct MHD_Semaphore *sem) | ||
112 | { | ||
113 | if (! pthread_mutex_lock (&sem->mutex)) | ||
114 | MHD_PANIC ("pthread_mutex_lock for semaphore failed\n"); | ||
115 | sem->counter++; | ||
116 | pthread_cond_signal (&sem->cv); | ||
117 | if (! pthread_mutex_unlock (&sem->mutex)) | ||
118 | MHD_PANIC ("pthread_mutex_unlock for semaphore failed\n"); | ||
119 | } | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Destroys the semaphore. | ||
124 | * | ||
125 | * @param sem semaphore to destroy. | ||
126 | */ | ||
127 | void | ||
128 | MHD_semaphore_destroy (struct MHD_Semaphore *sem) | ||
129 | { | ||
130 | if (0 != pthread_cond_destroy (&sem->cv)) | ||
131 | MHD_PANIC ("pthread_cond_destroy failed\n"); | ||
132 | if (0 != pthread_mutex_destroy (&sem->mutex)) | ||
133 | MHD_PANIC ("pthread_mutex_destroy failed\n"); | ||
134 | free (sem); | ||
135 | } | ||
136 | |||
137 | |||
138 | /* end of mhd_sem.c */ | ||
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index 670be983..ca729765 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c | |||
@@ -605,7 +605,23 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
605 | switch (action) | 605 | switch (action) |
606 | { | 606 | { |
607 | case MHD_UPGRADE_ACTION_CLOSE: | 607 | case MHD_UPGRADE_ACTION_CLOSE: |
608 | /* transition to special 'closed' state for start of cleanup */ | ||
609 | connection->state = MHD_CONNECTION_UPGRADE_CLOSED; | ||
608 | /* Application is done with this connection, tear it down! */ | 610 | /* Application is done with this connection, tear it down! */ |
611 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) | ||
612 | { | ||
613 | if (0 == (daemon->options & MHD_USE_SSL) ) | ||
614 | { | ||
615 | /* just need to signal the thread that we are done */ | ||
616 | MHD_semaphore_up (connection->upgrade_sem); | ||
617 | } | ||
618 | else | ||
619 | { | ||
620 | /* signal thread by shutdown() of 'app' socket */ | ||
621 | shutdown (urh->app.socket, SHUT_RDWR); | ||
622 | } | ||
623 | return MHD_YES; | ||
624 | } | ||
609 | #if HTTPS_SUPPORT | 625 | #if HTTPS_SUPPORT |
610 | if (0 != (daemon->options & MHD_USE_SSL) ) | 626 | if (0 != (daemon->options & MHD_USE_SSL) ) |
611 | { | 627 | { |
@@ -658,6 +674,9 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
658 | case MHD_UPGRADE_ACTION_CORK: | 674 | case MHD_UPGRADE_ACTION_CORK: |
659 | /* FIXME: not implemented */ | 675 | /* FIXME: not implemented */ |
660 | return MHD_NO; | 676 | return MHD_NO; |
677 | case MHD_UPGRADE_ACTION_FLUSH: | ||
678 | /* FIXME: not implemented */ | ||
679 | return MHD_NO; | ||
661 | default: | 680 | default: |
662 | /* we don't understand this one */ | 681 | /* we don't understand this one */ |
663 | return MHD_NO; | 682 | return MHD_NO; |
@@ -784,11 +803,6 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
784 | rbo, | 803 | rbo, |
785 | urh->app.socket, | 804 | urh->app.socket, |
786 | urh); | 805 | urh); |
787 | /* As far as MHD is concerned, this connection is | ||
788 | suspended; it will be resumed once we are done | ||
789 | in the #MHD_upgrade_action() function */ | ||
790 | MHD_suspend_connection (connection); | ||
791 | |||
792 | /* Launch IO processing by the event loop */ | 806 | /* Launch IO processing by the event loop */ |
793 | if (0 != (daemon->options & MHD_USE_EPOLL)) | 807 | if (0 != (daemon->options & MHD_USE_EPOLL)) |
794 | { | 808 | { |
@@ -846,12 +860,25 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
846 | return MHD_NO; | 860 | return MHD_NO; |
847 | } | 861 | } |
848 | } | 862 | } |
849 | 863 | if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) | |
850 | /* This takes care of most event loops: simply add to DLL */ | 864 | { |
851 | DLL_insert (daemon->urh_head, | 865 | /* As far as MHD's event loops are concerned, this connection |
852 | daemon->urh_tail, | 866 | is suspended; it will be resumed once we are done in the |
853 | urh); | 867 | #MHD_upgrade_action() function */ |
854 | /* FIXME: None of the above will not work (yet) for thread-per-connection processing */ | 868 | MHD_suspend_connection (connection); |
869 | /* This takes care of further processing for most event loops: | ||
870 | simply add to DLL for bi-direcitonal processing */ | ||
871 | DLL_insert (daemon->urh_head, | ||
872 | daemon->urh_tail, | ||
873 | urh); | ||
874 | } | ||
875 | else | ||
876 | { | ||
877 | /* Our caller will set 'connection->state' to | ||
878 | MHD_CONNECTION_UPGRADE, thereby triggering the main method | ||
879 | of the thread to switch to bi-directional forwarding. */ | ||
880 | connection->urh = urh; | ||
881 | } | ||
855 | return MHD_YES; | 882 | return MHD_YES; |
856 | } | 883 | } |
857 | urh->app.socket = MHD_INVALID_SOCKET; | 884 | urh->app.socket = MHD_INVALID_SOCKET; |
@@ -864,10 +891,31 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
864 | rbo, | 891 | rbo, |
865 | connection->socket_fd, | 892 | connection->socket_fd, |
866 | urh); | 893 | urh); |
867 | /* As far as MHD is concerned, this connection is | 894 | if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) |
868 | suspended; it will be resumed once we are done | 895 | { |
869 | in the #MHD_upgrade_action() function */ | 896 | /* Need to give the thread something to block on... */ |
870 | MHD_suspend_connection (connection); | 897 | connection->upgrade_sem = MHD_semaphore_create (0); |
898 | if (NULL == connection->upgrade_sem) | ||
899 | { | ||
900 | #ifdef HAVE_MESSAGES | ||
901 | MHD_DLOG (daemon, | ||
902 | "Failed to create semaphore for upgrade handling\n"); | ||
903 | #endif | ||
904 | MHD_connection_close_ (connection, | ||
905 | MHD_REQUEST_TERMINATED_WITH_ERROR); | ||
906 | return MHD_NO; | ||
907 | } | ||
908 | /* Our caller will set 'connection->state' to | ||
909 | MHD_CONNECTION_UPGRADE, thereby triggering the | ||
910 | main method of the thread to block on the semaphore. */ | ||
911 | } | ||
912 | else | ||
913 | { | ||
914 | /* As far as MHD's event loops are concerned, this connection is | ||
915 | suspended; it will be resumed once we are done in the | ||
916 | #MHD_upgrade_action() function */ | ||
917 | MHD_suspend_connection (connection); | ||
918 | } | ||
871 | return MHD_YES; | 919 | return MHD_YES; |
872 | } | 920 | } |
873 | 921 | ||