diff options
Diffstat (limited to 'src/microhttpd/response.c')
-rw-r--r-- | src/microhttpd/response.c | 144 |
1 files changed, 120 insertions, 24 deletions
diff --git a/src/microhttpd/response.c b/src/microhttpd/response.c index e778ed7f..670be983 100644 --- a/src/microhttpd/response.c +++ b/src/microhttpd/response.c | |||
@@ -599,7 +599,8 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
599 | enum MHD_UpgradeAction action, | 599 | enum MHD_UpgradeAction action, |
600 | ...) | 600 | ...) |
601 | { | 601 | { |
602 | struct MHD_Daemon *daemon = urh->connection->daemon; | 602 | struct MHD_Connection *connection = urh->connection; |
603 | struct MHD_Daemon *daemon = connection->daemon; | ||
603 | 604 | ||
604 | switch (action) | 605 | switch (action) |
605 | { | 606 | { |
@@ -611,18 +612,46 @@ MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, | |||
611 | DLL_remove (daemon->urh_head, | 612 | DLL_remove (daemon->urh_head, |
612 | daemon->urh_tail, | 613 | daemon->urh_tail, |
613 | urh); | 614 | urh); |
614 | /* FIXME: if running in epoll()-mode, do we have | 615 | if (0 != (daemon->options & MHD_USE_EPOLL)) |
615 | to remove any of the FDs from any epoll-sets here? */ | 616 | { |
616 | if ( (MHD_INVALID_SOCKET != urh->app_socket) && | 617 | /* epoll documentation suggests that closing a FD |
617 | (0 != MHD_socket_close_ (urh->app_socket)) ) | 618 | automatically removes it from the epoll set; however, |
618 | MHD_PANIC ("close failed\n"); | 619 | this is not true as if we fail to do manually remove it, |
619 | if ( (MHD_INVALID_SOCKET != urh->mhd_socket) && | 620 | we are still seeing an event for this fd in epoll, |
620 | (0 != MHD_socket_close_ (urh->mhd_socket)) ) | 621 | causing grief (use-after-free...) --- at least on my |
621 | MHD_PANIC ("close failed\n"); | 622 | system. */ |
623 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
624 | EPOLL_CTL_DEL, | ||
625 | connection->socket_fd, | ||
626 | NULL)) | ||
627 | MHD_PANIC ("Failed to remove FD from epoll set\n"); | ||
628 | } | ||
629 | if (MHD_INVALID_SOCKET != urh->app.socket) | ||
630 | { | ||
631 | if (0 != MHD_socket_close_ (urh->app.socket)) | ||
632 | MHD_PANIC ("close failed\n"); | ||
633 | } | ||
634 | if (MHD_INVALID_SOCKET != urh->mhd.socket) | ||
635 | { | ||
636 | /* epoll documentation suggests that closing a FD | ||
637 | automatically removes it from the epoll set; however, | ||
638 | this is not true as if we fail to do manually remove it, | ||
639 | we are still seeing an event for this fd in epoll, | ||
640 | causing grief (use-after-free...) --- at least on my | ||
641 | system. */ | ||
642 | if ( (0 != (daemon->options & MHD_USE_EPOLL)) && | ||
643 | (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
644 | EPOLL_CTL_DEL, | ||
645 | urh->mhd.socket, | ||
646 | NULL)) ) | ||
647 | MHD_PANIC ("Failed to remove FD from epoll set\n"); | ||
648 | if (0 != MHD_socket_close_ (urh->mhd.socket)) | ||
649 | MHD_PANIC ("close failed\n"); | ||
650 | } | ||
622 | } | 651 | } |
623 | #endif | 652 | #endif |
624 | MHD_resume_connection (urh->connection); | 653 | MHD_resume_connection (connection); |
625 | MHD_connection_close_ (urh->connection, | 654 | MHD_connection_close_ (connection, |
626 | MHD_REQUEST_TERMINATED_COMPLETED_OK); | 655 | MHD_REQUEST_TERMINATED_COMPLETED_OK); |
627 | free (urh); | 656 | free (urh); |
628 | return MHD_YES; | 657 | return MHD_YES; |
@@ -691,6 +720,15 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
691 | free (urh); | 720 | free (urh); |
692 | return MHD_NO; | 721 | return MHD_NO; |
693 | } | 722 | } |
723 | if ( (! MHD_itc_nonblocking_(sv[0])) || | ||
724 | (! MHD_itc_nonblocking_(sv[1])) ) | ||
725 | { | ||
726 | #ifdef HAVE_MESSAGES | ||
727 | MHD_DLOG (daemon, | ||
728 | "Failed to make read side of inter-thread control channel non-blocking: %s\n", | ||
729 | MHD_pipe_last_strerror_ ()); | ||
730 | #endif | ||
731 | } | ||
694 | if ( (! MHD_SCKT_FD_FITS_FDSET_(sv[1], NULL)) && | 732 | if ( (! MHD_SCKT_FD_FITS_FDSET_(sv[1], NULL)) && |
695 | (0 == (daemon->options & (MHD_USE_POLL | MHD_USE_EPOLL))) ) | 733 | (0 == (daemon->options & (MHD_USE_POLL | MHD_USE_EPOLL))) ) |
696 | { | 734 | { |
@@ -707,8 +745,12 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
707 | free (urh); | 745 | free (urh); |
708 | return MHD_NO; | 746 | return MHD_NO; |
709 | } | 747 | } |
710 | urh->app_socket = sv[0]; | 748 | urh->app.socket = sv[0]; |
711 | urh->mhd_socket = sv[1]; | 749 | urh->app.urh = urh; |
750 | urh->app.celi = MHD_EPOLL_STATE_UNREADY; | ||
751 | urh->mhd.socket = sv[1]; | ||
752 | urh->mhd.urh = urh; | ||
753 | urh->mhd.celi = MHD_EPOLL_STATE_UNREADY; | ||
712 | pool = connection->pool; | 754 | pool = connection->pool; |
713 | avail = MHD_pool_get_free (pool); | 755 | avail = MHD_pool_get_free (pool); |
714 | if (avail < 8) | 756 | if (avail < 8) |
@@ -740,26 +782,80 @@ MHD_response_execute_upgrade_ (struct MHD_Response *response, | |||
740 | connection->client_context, | 782 | connection->client_context, |
741 | connection->read_buffer, | 783 | connection->read_buffer, |
742 | rbo, | 784 | rbo, |
743 | urh->app_socket, | 785 | urh->app.socket, |
744 | urh); | 786 | urh); |
745 | /* As far as MHD is concerned, this connection is | 787 | /* As far as MHD is concerned, this connection is |
746 | suspended; it will be resumed once we are done | 788 | suspended; it will be resumed once we are done |
747 | in the #MHD_upgrade_action() function */ | 789 | in the #MHD_upgrade_action() function */ |
748 | MHD_suspend_connection (connection); | 790 | MHD_suspend_connection (connection); |
749 | urh->celi_mhd = MHD_EPOLL_STATE_UNREADY; | 791 | |
750 | urh->celi_client = MHD_EPOLL_STATE_UNREADY; | ||
751 | /* FIXME: is it possible we did not fully drain the client | ||
752 | socket yet and are thus read-ready already? This may | ||
753 | matter if we are in epoll() edge triggered mode... */ | ||
754 | /* Launch IO processing by the event loop */ | 792 | /* Launch IO processing by the event loop */ |
755 | /* FIXME: this will not work (yet) for thread-per-connection processing */ | 793 | if (0 != (daemon->options & MHD_USE_EPOLL)) |
756 | DLL_insert (connection->daemon->urh_head, | 794 | { |
757 | connection->daemon->urh_tail, | 795 | /* We're running with epoll(), need to add the sockets |
796 | to the event set of the daemon's `epoll_upgrade_fd` */ | ||
797 | struct epoll_event event; | ||
798 | |||
799 | EXTRA_CHECK (MHD_SOCKET_INVALID != daemon->epoll_upgrade_fd); | ||
800 | /* First, add network socket */ | ||
801 | event.events = EPOLLIN | EPOLLOUT; | ||
802 | event.data.ptr = &urh->app; | ||
803 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
804 | EPOLL_CTL_ADD, | ||
805 | connection->socket_fd, | ||
806 | &event)) | ||
807 | { | ||
808 | #ifdef HAVE_MESSAGES | ||
809 | MHD_DLOG (daemon, | ||
810 | "Call to epoll_ctl failed: %s\n", | ||
811 | MHD_socket_last_strerr_ ()); | ||
812 | #endif | ||
813 | if (0 != MHD_socket_close_ (sv[0])) | ||
814 | MHD_PANIC ("close failed\n"); | ||
815 | if (0 != MHD_socket_close_ (sv[1])) | ||
816 | MHD_PANIC ("close failed\n"); | ||
817 | free (urh); | ||
818 | return MHD_NO; | ||
819 | } | ||
820 | |||
821 | /* Second, add our end of the UNIX socketpair() */ | ||
822 | event.events = EPOLLIN | EPOLLOUT; | ||
823 | event.data.ptr = &urh->mhd; | ||
824 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
825 | EPOLL_CTL_ADD, | ||
826 | urh->mhd.socket, | ||
827 | &event)) | ||
828 | { | ||
829 | event.events = EPOLLIN | EPOLLOUT; | ||
830 | event.data.ptr = &urh->app; | ||
831 | if (0 != epoll_ctl (daemon->epoll_upgrade_fd, | ||
832 | EPOLL_CTL_DEL, | ||
833 | connection->socket_fd, | ||
834 | &event)) | ||
835 | MHD_PANIC ("Error cleaning up while handling epoll error"); | ||
836 | #ifdef HAVE_MESSAGES | ||
837 | MHD_DLOG (daemon, | ||
838 | "Call to epoll_ctl failed: %s\n", | ||
839 | MHD_socket_last_strerr_ ()); | ||
840 | #endif | ||
841 | if (0 != MHD_socket_close_ (sv[0])) | ||
842 | MHD_PANIC ("close failed\n"); | ||
843 | if (0 != MHD_socket_close_ (sv[1])) | ||
844 | MHD_PANIC ("close failed\n"); | ||
845 | free (urh); | ||
846 | return MHD_NO; | ||
847 | } | ||
848 | } | ||
849 | |||
850 | /* This takes care of most event loops: simply add to DLL */ | ||
851 | DLL_insert (daemon->urh_head, | ||
852 | daemon->urh_tail, | ||
758 | urh); | 853 | urh); |
854 | /* FIXME: None of the above will not work (yet) for thread-per-connection processing */ | ||
759 | return MHD_YES; | 855 | return MHD_YES; |
760 | } | 856 | } |
761 | urh->app_socket = MHD_INVALID_SOCKET; | 857 | urh->app.socket = MHD_INVALID_SOCKET; |
762 | urh->mhd_socket = MHD_INVALID_SOCKET; | 858 | urh->mhd.socket = MHD_INVALID_SOCKET; |
763 | #endif | 859 | #endif |
764 | response->upgrade_handler (response->upgrade_handler_cls, | 860 | response->upgrade_handler (response->upgrade_handler_cls, |
765 | connection, | 861 | connection, |