diff --git a/res/miracle-wfdctl-demo b/res/miracle-wfdctl-demo index 32e241d..630dc3e 100755 --- a/res/miracle-wfdctl-demo +++ b/res/miracle-wfdctl-demo @@ -103,10 +103,10 @@ get_prop() cleanup() { - kill 0 - set -x - for (( i=${#cleanup[@]}-1; i>=0; --i )); do - eval ${cleanup[$i]} || true + set +e + while (( 0 != ${#cleanup[@]} )); do + eval ${cleanup[${#cleanup[@]}-1]} + unset cleanup[${#cleanup[@]}-1] done } @@ -115,6 +115,14 @@ cleanup_push() cleanup+=("$*") } +nm_manage() +{ + set_prop org.freedesktop.NetworkManager \ + /org/freedesktop/NetworkManager/Devices/"$nm_link_index" \ + org.freedesktop.NetworkManager.Device \ + Managed b true +} + link_unmanage() { set_prop org.freedesktop.miracle.wifi \ @@ -149,6 +157,7 @@ set_prop org.freedesktop.NetworkManager \ /org/freedesktop/NetworkManager/Devices/"$nm_link_index" \ org.freedesktop.NetworkManager.Device \ Managed b false +cleanup_push nm_manage set_prop org.freedesktop.miracle.wifi \ /org/freedesktop/miracle/wifi/link/$link_index \ org.freedesktop.miracle.wifi.Link \ @@ -179,6 +188,8 @@ get_prop org.freedesktop.miracle.wifi \ org.freedesktop.miracle.wifi.Peer \ Interface p2p_iface tcpdump -nnvvXS -s 0 -i $p2p_iface port 7236 or port 67 or port 68 & +cleanup_push "kill $!" + while ! killall -0 miracle-wfdctl && [[ -z "$nocheck" ]] &>/dev/null; do echo please run miracle-wfdctl manually sleep 3 diff --git a/src/ctl/ctl.h b/src/ctl/ctl.h index 09534ce..6b0fd37 100644 --- a/src/ctl/ctl.h +++ b/src/ctl/ctl.h @@ -198,6 +198,8 @@ struct wfd_sink union wfd_sube dev_info; char *label; struct wfd_session *session; + + sd_event_source *session_cleanup_source; }; int wfd_sink_new(struct wfd_sink **out, @@ -237,6 +239,8 @@ struct ctl_wfd struct shl_htable sessions; size_t n_sessions; uint64_t id_pool; + + sd_event_source *signal_sources[4]; }; struct ctl_wfd * ctl_wfd_get(); diff --git a/src/ctl/wfd-dbus.c b/src/ctl/wfd-dbus.c index 07911f8..5feccc2 100644 --- a/src/ctl/wfd-dbus.c +++ b/src/ctl/wfd-dbus.c @@ -163,7 +163,7 @@ int _wfd_dbus_object_removed(struct wfd_dbus *wfd_dbus, size_t n_ifaces) { int i, r; - _sd_bus_message_unref_ sd_bus_message *m; + _sd_bus_message_unref_ sd_bus_message *m = NULL; if(!wfd_dbus) { return -ECANCELED; @@ -209,7 +209,7 @@ int _wfd_dbus_object_added(struct wfd_dbus *wfd_dbus, size_t n_ifaces) { int i, r; - _sd_bus_message_unref_ sd_bus_message *m; + _sd_bus_message_unref_ sd_bus_message *m = NULL; if(!wfd_dbus) { return -ECANCELED; @@ -251,7 +251,7 @@ int _wfd_dbus_object_added(struct wfd_dbus *wfd_dbus, int wfd_fn_sink_new(struct wfd_sink *s) { - _shl_free_ char *path; + _shl_free_ char *path = NULL; int r = sd_bus_path_encode("/org/freedesktop/miracle/wfd/sink", wfd_sink_get_label(s), &path); @@ -264,7 +264,7 @@ int wfd_fn_sink_new(struct wfd_sink *s) int wfd_fn_sink_free(struct wfd_sink *s) { - _shl_free_ char *path; + _shl_free_ char *path = NULL; int r = sd_bus_path_encode("/org/freedesktop/miracle/wfd/sink", wfd_sink_get_label(s), &path); @@ -277,7 +277,7 @@ int wfd_fn_sink_free(struct wfd_sink *s) int _wfd_fn_sink_properties_changed(struct wfd_sink *s, char **names) { - _shl_free_ char *path; + _shl_free_ char *path = NULL; int r; struct wfd_dbus *wfd_dbus = wfd_dbus_get(); @@ -322,7 +322,7 @@ static int wfd_dbus_find_sink(sd_bus *bus, int wfd_fn_session_new(struct wfd_session *s) { - _shl_free_ char *path; + _shl_free_ char *path = NULL; int r = wfd_dbus_get_session_path(s, &path); if(0 > r) { return r; @@ -333,7 +333,7 @@ int wfd_fn_session_new(struct wfd_session *s) int wfd_fn_session_free(struct wfd_session *s) { - _shl_free_ char *path; + _shl_free_ char *path = NULL; int r = wfd_dbus_get_session_path(s, &path); if(0 > r) { return r; @@ -424,6 +424,30 @@ static int wfd_dbus_sink_start_session(sd_bus_message *m, // return 0; //} +static int wfd_dbus_sink_get_session(sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *ret_error) +{ + struct wfd_sink *s = userdata; + _shl_free_ char *session_path = NULL; + int r; + + if(!s->session) { + return 0; + } + + r = wfd_dbus_get_session_path(s->session, &session_path); + if(0 > r) { + return r; + } + + return sd_bus_message_append(reply, "o", session_path); +} + static int wfd_dbus_sink_get_peer(sd_bus *bus, const char *path, const char *interface, @@ -433,7 +457,7 @@ static int wfd_dbus_sink_get_peer(sd_bus *bus, sd_bus_error *ret_error) { struct wfd_sink *s = userdata; - _shl_free_ char *peer_path; + _shl_free_ char *peer_path = NULL; int r = sd_bus_path_encode("/org/freedesktop/miracle/wifi/peer", s->label, &peer_path); @@ -560,7 +584,7 @@ static int wfd_dbus_get_session_state(sd_bus *bus, int _wfd_fn_session_properties_changed(struct wfd_session *s, char **names) { - _shl_free_ char *path; + _shl_free_ char *path = NULL; int r; struct wfd_dbus *wfd_dbus = wfd_dbus_get(); @@ -591,6 +615,7 @@ static const sd_bus_vtable wfd_dbus_sink_vtable[] = { /*SD_BUS_PROPERTY("VideoFormats", "a{sv}", wfd_dbus_sink_get_video_formats, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/ /*SD_BUS_PROPERTY("HasAudio", "b", wfd_dbus_sink_has_audio, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/ /*SD_BUS_PROPERTY("HasVideo", "b", wfd_dbus_sink_has_video, 0, SD_BUS_VTABLE_PROPERTY_CONST),*/ + SD_BUS_PROPERTY("Session", "o", wfd_dbus_sink_get_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Peer", "o", wfd_dbus_sink_get_peer, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END, }; diff --git a/src/ctl/wfd-out-session.c b/src/ctl/wfd-out-session.c index b30cce4..33764fc 100644 --- a/src/ctl/wfd-out-session.c +++ b/src/ctl/wfd-out-session.c @@ -30,10 +30,13 @@ struct wfd_out_session struct wfd_session parent; struct wfd_sink *sink; int fd; + sd_event_source *gst_term_source; }; static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[]; +#include + int wfd_out_session_new(struct wfd_session **out, struct wfd_sink *sink) { struct wfd_out_session *s = calloc(1, sizeof(struct wfd_out_session)); @@ -164,9 +167,14 @@ int wfd_out_session_initiate_io(struct wfd_session *s, static void wfd_out_session_kill_gst(struct wfd_session *s) { - if(-1 != s->stream.gst) { - kill(s->stream.gst, SIGTERM); - s->stream.gst = -1; + pid_t pid; + struct wfd_out_session *os = wfd_out_session(s); + if(os->gst_term_source) { + sd_event_source_get_child_pid(os->gst_term_source, &pid); + kill(pid, SIGTERM); + + sd_event_source_set_userdata(os->gst_term_source, NULL); + os->gst_term_source = NULL; } } @@ -191,20 +199,15 @@ int wfd_out_session_teardown(struct wfd_session *s) &(struct wfd_arg_list) wfd_arg_list(wfd_arg_cstr("TEARDOWN"))); } -void wfd_out_session_end(struct wfd_session *s) +void wfd_out_session_destroy(struct wfd_session *s) { struct wfd_out_session *os = wfd_out_session(s); - - wfd_out_session_kill_gst(s); - if(0 <= os->fd) { close(os->fd); os->fd = -1; } -} -void wfd_out_session_distruct(struct wfd_session *s) -{ + wfd_out_session_kill_gst(s); } int wfd_out_session_initiate_request(struct wfd_session *s) @@ -305,7 +308,6 @@ static int wfd_out_session_request_get_parameter(struct wfd_session *s, return 0; error: - wfd_session_end(s); return r; } @@ -425,7 +427,6 @@ static int wfd_out_session_launch_gst(struct wfd_session *s, pid_t *out) char port[10]; char * args[] = { "gst-launch-1.0", - "-v", "ximagesrc", "use-damage=false", "show-pointer=false", @@ -473,9 +474,21 @@ static int wfd_out_session_handle_gst_term(sd_event_source *source, const siginfo_t *si, void *userdata) { + struct wfd_out_session *os = userdata; + log_trace("gst-launch(%d) terminated", si->si_pid); - wfd_session_end(userdata); + sd_event_source_unref(source); + + if(!os) { + return 0; + } + + os->gst_term_source = NULL; + + if(WFD_SESSION_STATE_PAUSED != wfd_session(os)->state) { + wfd_session_teardown(wfd_session(os)); + } return 0; } @@ -530,7 +543,7 @@ static int wfd_out_session_handle_play_request(struct wfd_session *s, struct rtsp_message *req, struct rtsp_message **out_rep) { - _shl_free_ char *v; + _shl_free_ char *v = NULL; _rtsp_message_unref_ struct rtsp_message *m = NULL; pid_t gst; int r, status; @@ -564,22 +577,21 @@ static int wfd_out_session_handle_play_request(struct wfd_session *s, } r = sd_event_add_child(ctl_wfd_get_loop(), - NULL, + &wfd_out_session(s)->gst_term_source, gst, WEXITED, wfd_out_session_handle_gst_term, s); if(0 > r) { kill(gst, SIGKILL); waitpid(gst, &status, WNOHANG); - return r; + wfd_session_teardown(s); + } + else { + *out_rep = m; + m = NULL; } - s->stream.gst = gst; - - *out_rep = m; - m = NULL; - - return 0; + return r; } static int wfd_out_session_handle_setup_request(struct wfd_session *s, @@ -698,7 +710,7 @@ static int wfd_out_session_request_set_parameter(struct wfd_session *s, const struct wfd_arg_list *args, struct rtsp_message **out) { - _rtsp_message_unref_ struct rtsp_message *m; + _rtsp_message_unref_ struct rtsp_message *m = NULL; _shl_free_ char *body = NULL; int r; diff --git a/src/ctl/wfd-session.c b/src/ctl/wfd-session.c index 1b18cba..ad25420 100644 --- a/src/ctl/wfd-session.c +++ b/src/ctl/wfd-session.c @@ -43,7 +43,7 @@ extern int wfd_out_session_resume(struct wfd_session *); extern int wfd_out_session_pause(struct wfd_session *); extern int wfd_out_session_teardown(struct wfd_session *); extern void wfd_out_session_end(struct wfd_session *); -extern void wfd_out_session_distruct(struct wfd_session *); +extern void wfd_out_session_destroy(struct wfd_session *); const struct wfd_session_vtable session_vtbl[] = { [WFD_SESSION_DIR_OUT] = { @@ -53,8 +53,7 @@ const struct wfd_session_vtable session_vtbl[] = { .resume = wfd_out_session_resume, .pause = wfd_out_session_pause, .teardown = wfd_out_session_teardown, - .end = wfd_out_session_end, - .distruct = wfd_out_session_distruct, + .destroy = wfd_out_session_destroy, } }; @@ -178,6 +177,9 @@ int wfd_session_teardown(struct wfd_session *s) { assert(wfd_is_session(s)); + /* notify and detach from sink */ + wfd_fn_out_session_ended(s); + if(wfd_session_is_established(s)) { if(!session_vtbl[s->dir].teardown) { return 0; @@ -186,41 +188,21 @@ int wfd_session_teardown(struct wfd_session *s) return session_vtbl[s->dir].teardown(s);; } - wfd_session_end(s); + wfd_session_free(s); return 0; } -void wfd_session_end(struct wfd_session *s) -{ - assert(wfd_is_session(s)); - - if(WFD_SESSION_STATE_NULL == s->state) { - return; - } - - log_info("session %lu ended", s->id); - - wfd_session_set_state(s, WFD_SESSION_STATE_NULL); - - (*session_vtbl[s->dir].end)(s); - - if(s->rtsp) { - rtsp_unref(s->rtsp); - s->rtsp = NULL; - } - - if(wfd_is_out_session(s)) { - wfd_fn_out_session_ended(s); - } -} - void wfd_session_free(struct wfd_session *s) { if(!s) { return; } + if(session_vtbl[s->dir].destroy) { + (*session_vtbl[s->dir].destroy)(s); + } + if(s->vformats) { wfd_video_formats_free(s->vformats); s->vformats = NULL; @@ -236,16 +218,15 @@ void wfd_session_free(struct wfd_session *s) s->stream.url = NULL; } + if(s->rtsp) { + rtsp_unref(s->rtsp); + s->rtsp = NULL; + } + s->rtp_ports[0] = 0; s->rtp_ports[1] = 0; s->last_request = RTSP_M_UNKNOWN; - wfd_session_end(s); - - if(session_vtbl[s->dir].distruct) { - (*session_vtbl[s->dir].distruct)(s); - } - free(s); } @@ -401,6 +382,10 @@ static int wfd_session_post_handle_request_n_reply(struct wfd_session *s, if(RTSP_M_UNKNOWN != next_request) { return wfd_session_request(s, next_request, req_args); } + + if(WFD_SESSION_STATE_TEARING_DOWN == new_state) { + wfd_fn_out_session_ended(s); + } return 0; } @@ -454,7 +439,7 @@ static int wfd_session_handle_request(struct rtsp *bus, return 0; error: - wfd_session_end(s); + wfd_session_teardown(s); return r; @@ -498,7 +483,8 @@ static int wfd_session_handle_reply(struct rtsp *bus, return 0; error: - wfd_session_end(s); + wfd_session_teardown(s); + return r; } @@ -552,6 +538,7 @@ static int wfd_session_handle_io(sd_event_source *source, _rtsp_unref_ struct rtsp *rtsp = NULL; sd_event_source_set_enabled(source, SD_EVENT_OFF); + sd_event_source_unref(source); if (mask & EPOLLERR) { r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len); @@ -597,7 +584,7 @@ static int wfd_session_handle_io(sd_event_source *source, end: if (0 > r) { - wfd_session_end(s); + wfd_session_teardown(s); } return r; diff --git a/src/ctl/wfd-session.h b/src/ctl/wfd-session.h index dd2111a..fce7c45 100644 --- a/src/ctl/wfd-session.h +++ b/src/ctl/wfd-session.h @@ -25,7 +25,6 @@ #define wfd_out_session(s) (assert(wfd_is_out_session(s)), (struct wfd_out_session *) (s)) #define wfd_in_session(s) (assert(wfd_is_in_session(s)), (struct wfd_in_session *) (s)) -#define wfd_session_is_destructed(s) (!(s) || (s)->destructed) struct wfd_session; struct wfd_sink; @@ -89,8 +88,7 @@ struct wfd_session_vtable int (*resume)(struct wfd_session *); int (*pause)(struct wfd_session *); int (*teardown)(struct wfd_session *); - void (*end)(struct wfd_session *s); - void (*distruct)(struct wfd_session *s); + void (*destroy)(struct wfd_session *s); }; struct wfd_session @@ -110,7 +108,6 @@ struct wfd_session enum wfd_stream_id id; char *url; uint16_t rtp_port; - pid_t gst; } stream; }; diff --git a/src/ctl/wfd-sink.c b/src/ctl/wfd-sink.c index 088ebb9..9d8436a 100644 --- a/src/ctl/wfd-sink.c +++ b/src/ctl/wfd-sink.c @@ -24,6 +24,34 @@ #include "ctl.h" #include "wfd-dbus.h" +static int wfd_sink_set_session(struct wfd_sink *sink, + struct wfd_session *session) +{ + int r; + + if(sink->session == session) { + return 0; + } + + if(session) { + r = ctl_wfd_add_session(ctl_wfd_get(), session); + if(0 > r) { + return r; + } + } + + if(sink->session) { + ctl_wfd_remove_session_by_id(ctl_wfd_get(), + wfd_session_get_id(sink->session), + NULL); + } + + sink->session = session; + wfd_fn_sink_properties_changed(sink, "Session"); + + return 0; +} + int wfd_sink_new(struct wfd_sink **out, struct ctl_peer *peer, union wfd_sube *sube) @@ -55,12 +83,16 @@ int wfd_sink_new(struct wfd_sink **out, void wfd_sink_free(struct wfd_sink *sink) { + struct wfd_session *s; + if(!sink) { return; } if(sink->session) { - wfd_session_free(sink->session); + s = sink->session; + wfd_sink_set_session(sink, NULL); + wfd_session_free(s); } if(sink->label) { @@ -107,7 +139,7 @@ int wfd_sink_start_session(struct wfd_sink *sink, struct wfd_session **out) return r; } - r = ctl_wfd_add_session(ctl_wfd_get(), s); + r = wfd_sink_set_session(sink, s); if(0 > r) { return r; } @@ -121,43 +153,13 @@ int wfd_sink_start_session(struct wfd_sink *sink, struct wfd_session **out) return 0; } -static int wfd_sink_defered_session_cleanup(sd_event_source *source, - uint64_t used, - void *userdata) -{ - struct wfd_session *s = userdata; - - sd_event_source_set_enabled(source, false); - - ctl_wfd_remove_session_by_id(ctl_wfd_get(), - wfd_session_get_id(s), - NULL); - wfd_session_free(s); - - return 0; -} - int wfd_fn_out_session_ended(struct wfd_session *s) { - struct wfd_sink *sink; - uint64_t now = 0; - assert(wfd_is_out_session(s)); - sink = wfd_out_session_get_sink(s); - sink->session = NULL; + wfd_sink_set_session(wfd_out_session_get_sink(s), NULL); - wfd_fn_sink_properties_changed(sink, "Session"); - - sd_event_now(ctl_wfd_get_loop(), CLOCK_MONOTONIC, &now); - - return sd_event_add_time(ctl_wfd_get_loop(), - NULL, - CLOCK_MONOTONIC, - 200 * 1000 + now, - 0, - wfd_sink_defered_session_cleanup, - s); + return 0; } bool wfd_sink_is_session_started(struct wfd_sink *sink) diff --git a/src/ctl/wfdctl.c b/src/ctl/wfdctl.c index 921f40e..76f6a7d 100644 --- a/src/ctl/wfdctl.c +++ b/src/ctl/wfdctl.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "ctl.h" #include "wfd.h" @@ -71,21 +72,25 @@ error: return r; } -static void ctl_wfd_destroy(struct ctl_wfd *wfd) -{ - ctl_wifi_free(wfd->wifi); - wfd->wifi = NULL; - shl_htable_clear_str(&wfd->sinks, NULL, NULL); - shl_htable_clear_u64(&wfd->sessions, NULL, NULL); -} - static void ctl_wfd_free(struct ctl_wfd *wfd) { + int i; + if(!wfd) { return; } - ctl_wfd_destroy(wfd); + ctl_wifi_free(wfd->wifi); + wfd->wifi = NULL; + shl_htable_clear_str(&wfd->sinks, NULL, NULL); + shl_htable_clear_u64(&wfd->sessions, NULL, NULL); + + for(i = 0; i < SHL_ARRAY_LENGTH(wfd->signal_sources); ++ i) { + if(wfd->signal_sources[i]) { + sd_event_source_set_enabled(wfd->signal_sources[i], SD_EVENT_OFF); + sd_event_source_unref(wfd->signal_sources[i]); + } + } if(wfd->loop) { sd_event_unref(wfd->loop); @@ -99,7 +104,7 @@ int ctl_wfd_add_sink(struct ctl_wfd *wfd, union wfd_sube *sube, struct wfd_sink **out) { - _wfd_sink_free_ struct wfd_sink *s; + _wfd_sink_free_ struct wfd_sink *s = NULL; int r = shl_htable_lookup_str(&wfd->sinks, p->label, NULL, @@ -223,7 +228,11 @@ int ctl_wfd_remove_session_by_id(struct ctl_wfd *wfd, static int ctl_wfd_fetch_info(sd_event_source *s, void *userdata) { struct ctl_wfd *wfd = userdata; - int r = ctl_wifi_fetch(wfd->wifi); + int r; + + sd_event_source_unref(s); + + r = ctl_wifi_fetch(wfd->wifi); if(0 > r) { log_warning("failed to fetch information about links and peers: %s", strerror(errno)); @@ -238,7 +247,8 @@ static int ctl_wfd_handle_signal(sd_event_source *s, void *userdata) { struct ctl_wfd *wfd = userdata; - ctl_wfd_destroy(wfd); + + sd_event_source_set_enabled(s, false); return sd_event_exit(wfd->loop, 0); } @@ -246,10 +256,12 @@ static int ctl_wfd_handle_signal(sd_event_source *s, static int ctl_wfd_init(struct ctl_wfd *wfd, sd_bus *bus) { int i, r; - const int signals[] = { SIGINT, SIGHUP, SIGQUIT, SIGTERM }; + const int signals[SHL_ARRAY_LENGTH(wfd->signal_sources)] = { + SIGINT, SIGHUP, SIGQUIT, SIGTERM + }; struct ctl_wifi *wifi; - for(i = 0; i < SHL_ARRAY_LENGTH(signals); i ++) { + for(i = 0; i < SHL_ARRAY_LENGTH(wfd->signal_sources); i ++) { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, signals[i]); @@ -259,7 +271,7 @@ static int ctl_wfd_init(struct ctl_wfd *wfd, sd_bus *bus) } r = sd_event_add_signal(wfd->loop, - NULL, + &wfd->signal_sources[i], signals[i], ctl_wfd_handle_signal, wfd); @@ -286,11 +298,6 @@ end: return r; } -int ctl_wfd_run(struct ctl_wfd *wfd) -{ - return sd_event_loop(wfd->loop); -} - /* Callbacks from ctl-src */ void wfd_fn_src_connected(struct wfd_src *s) { @@ -366,12 +373,7 @@ void ctl_fn_peer_free(struct ctl_peer *p) label = strdup(s->label); - r = wfd_fn_sink_free(s); - if(0 > r) { - log_warning("failed to unpublish removed sink (%s): %s", - wfd_sink_get_label(s), - strerror(errno)); - } + wfd_fn_sink_free(s); wfd_sink_free(s); @@ -417,6 +419,7 @@ void cli_fn_help() int main(int argc, char **argv) { int r; + sd_event *loop; sd_bus *bus; @@ -457,25 +460,26 @@ int main(int argc, char **argv) r = wfd_dbus_expose(wfd_dbus); if(0 > r) { log_warning("unabled to publish WFD service: %s", strerror(errno)); - goto free_ctl_wfd; + goto free_wfd_dbus; } - r = ctl_wfd_run(wfd); + r = sd_event_loop(loop); if(0 > r) { log_warning("unabled to keep WFD service running: %s", strerror(errno)); } +free_wfd_dbus: wfd_dbus_free(wfd_dbus); wfd_dbus = NULL; - free_ctl_wfd: ctl_wfd_free(wfd); wfd = NULL; bus_detach_event: sd_bus_detach_event(bus); unref_bus: - sd_bus_unref(bus); + sd_bus_flush_close_unref(bus); unref_loop: + sd_event_run(loop, 0); sd_event_unref(loop); end: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;