aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/response.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/response.c')
-rw-r--r--src/microhttpd/response.c144
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,