Hi On Thu, Feb 25, 2016 at 3:19 PM, Lukas Venhoda <lvenhoda@xxxxxxxxxx> wrote: > Try to connect to shared folder automatically on Windows. > > On each loop of run_service(), run a GTask, that waits for half a second. > If read_thread() returns, it means, that sharing is not yet connected, > and the map_drive task is cancelled. > > If the map_drive task is NOT cancelled, it enumerates free drive > letters, and maps shared folder to highest possible (from Z: to A:). > > If all drive letters are already assigned, stop the service. > --- > Changes since v1: > - Changed GThread to a GTask > - Only wait half a second, instead of 5 > > Changes since RFC: > - Calling WNetAddConnection2() blindly was slow and caause many threads to spawn. > - Now only call it once, when it is sure, that it will connect. > - Now connects to a * drive, instead of always Z: > - Thread is now spawned and joined every time run_service() is called. > --- > Makefile.am | 4 +++ > spice/spice-webdavd.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 85 insertions(+) > > diff --git a/Makefile.am b/Makefile.am > index 6127f93..d8e2d53 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -87,6 +87,10 @@ spice_webdavd_LDADD = \ > $(PIE_LDFLAGS) \ > $(NULL) > > +if OS_WIN32 > +spice_webdavd_LDADD += -lnetapi32 -lmpr > +endif > + > deps.txt: > $(AM_V_GEN)rpm -qa | grep $(host_os) | sort | unix2dos > $@ > > diff --git a/spice/spice-webdavd.c b/spice/spice-webdavd.c > index f9c5cf1..55b7bbb 100644 > --- a/spice/spice-webdavd.c > +++ b/spice/spice-webdavd.c > @@ -737,11 +737,88 @@ open_mux_path (const char *path) > mux_queue = output_queue_new (G_OUTPUT_STREAM (mux_ostream)); > } > > +#ifdef G_OS_WIN32 > +gchar drive_letter; > + > +static gchar > +get_free_drive_letter(void) > +{ > + const guint32 max_mask = 1 << 25; > + guint32 drives; > + guint32 mask; > + gint i; > + > + drives = GetLogicalDrives (); > + > + for (i = 0; i < 26; i++) > + { > + mask = max_mask >> i; > + if ((drives & mask) == 0) > + return 'Z' - i; > + } > + > + return 0; > +} > + > +static void > +map_drive(GTask *task, > + gpointer source_object, > + gpointer task_data, > + GCancellable *cancellable) > +{ > + static int loop_time = G_USEC_PER_SEC/10; > + GCancellable * cancel_map = task_data; > + gchar local_name[3]; > + gchar remote_name[] = "http://localhost:9843/"; > + NETRESOURCE net_resource; > + guint32 retval; > + gint i; > + > + for (i = 0; i < 5; ++i) > + { > + if (g_cancellable_is_cancelled (cancel_map)) > + return; > + else > + g_usleep (loop_time); > + } > + I am not sure I see the point of waiting 0.5s here. Add a comment? (a better way would be to use g_poll with the pollfd cancellable can creats: no need to loop) > + if ((drive_letter = get_free_drive_letter ()) == 0) > + g_error ("all drive letters already assigned."); This will abort(), I think it's better to have simply a critical. The webdav folder can be accessed through other means (browser etc) > + local_name[0] = drive_letter; > + local_name[1] = ':'; > + local_name[2] = 0; This is not strictly equivalent to "net use *", it will be racy. It probably needs to retry if the localname is already used. > + net_resource.dwType = RESOURCETYPE_DISK; > + net_resource.lpLocalName = local_name; > + net_resource.lpRemoteName = remote_name; > + net_resource.lpProvider = NULL; > + > + retval = WNetAddConnection2 (&net_resource, NULL, NULL, CONNECT_TEMPORARY); > + > + if (retval == NO_ERROR) > + g_debug ("map_drive ok"); > + else if (retval == ERROR_ALREADY_ASSIGNED) > + g_debug ("map_drive already asigned"); here, goto getfreedriver? > + else > + g_error ("map_drive error %d", retval); Please avoid g_error for non-fatal issues. The map-driver.bat file uses a nifty hack to name the folder "Spice client" (Spice folder would make more sense). It would be really nice to name the folder here too. > + > + return; > +} > +#endif > + > static void > run_service (void) > { > g_debug ("Run service"); > > +#ifdef G_OS_WIN32 > + GCancellable * cancel_map = g_cancellable_new (); > + GTask * map_drive_task = g_task_new (NULL, NULL, NULL, NULL); no unref? you probably should g_task_return() somewhere too. > + g_task_set_task_data (map_drive_task, cancel_map, NULL); > + g_task_run_in_thread (map_drive_task, map_drive); I think you could unref after this call, since run_in_thread() keeps a ref. Before adding and calling map_drive, I think you should implement the function to check if there is already a mapping. > +#endif > + > g_socket_service_start (socket_service); > > cancel = g_cancellable_new (); > @@ -775,6 +852,10 @@ run_service (void) > g_main_loop_run (loop); > g_main_loop_unref (loop); > > +#ifdef G_OS_WIN32 > + g_cancellable_cancel (cancel_map); no unref either? > +#endif > + > g_cancellable_cancel (cancel); > > g_clear_object (&mux_istream); > -- > 2.5.0 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/spice-devel -- Marc-André Lureau _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel