<div dir="ltr">Hi<br><div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Sep 17, 2015 at 12:23 PM, Marc-André Lureau <span dir="ltr"><<a href="mailto:marcandre.lureau@gmail.com" target="_blank">marcandre.lureau@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi<br>
<span><br>
On Thu, Aug 27, 2015 at 6:25 PM, Lukas Venhoda <<a href="mailto:lvenhoda@redhat.com" target="_blank">lvenhoda@redhat.com</a>> wrote:<br>
> Try to connect to shared folder automatically on Windows.<br>
><br>
> On each loop of run_service(), spawn a thread, that waits for 5 seconds.<br>
> If read_thread() returns, it means, that sharing is not yet connected,<br>
> and the map_drive thread is cancelled, and joined back to main thread.<br>
><br>
> If the map_drive thread is NOT cancelled, it enumerates free drive<br>
> letters, and maps shared folder to highest possible (from Z: to A:).<br>
><br>
> If all drive letters are already assigned, stop the service.<br>
<br>
</span>Could you explain in the commit message why you need the thread ?<br></blockquote><div><br></div><div>How about this commit message?<br><br><span>"Try to connect to shared folder automatically on Windows.<br></span><span><br>When client is connected, and sharing is enabled, map_drive is called.<br>It enumerates free drive letters, and maps shared folder to highest possible,<br>from (Z:) to (A:).
</span><span>If all drive letters are already assigned, stops the service.</span><br><br><span>map_drive needs to be called only after, the read_thread blocks.</span><br><span>If it is called before, the mapping fails.<br></span><span><span><br></span>In order to call it only after read_thread blocks, we spawn a thread,<br>that waits for 5 seconds, before</span><span> actually calling map_drive.</span><span><span><span><span><br>If read_thread() returns, it means, that sharing is not yet connected,<br>and the map_drive thread is cancelled.</span></span></span><br></span><br><span><span>We spawn this thread on each loop of run_service(), and join it back<br>into main_thread, after main loop ends</span>."<br></span></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
How do you prevent from having multiple drive pointing to the spice folder?<br>
<div><div><br></div></div></blockquote><div><br></div><div>Currently, I don't.<br></div><div><br>Only way to connect multiple drives, is if you restart the service,<br>because the drives will disconnect, after restarting guest.<br></div><div><br>I will add a disconnect function to the quit function in the service,<br>so that if uou disable, or restart teh service, the drive will be unmapped<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div>
<br>
> ---<br>
> Changes since RFC:<br>
>  - Calling WNetAddConnection2() blindly was slow and caause many threads to spawn.<br>
>     - Now only call it once, when it is sure, that it will connect.<br>
>  - Now connects to a * drive, instead of always Z:<br>
>  - Thread is now spawned and joined every time run_service() is called.<br>
> ---<br>
>  Makefile.am           |  4 +++<br>
>  spice/spice-webdavd.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++<br>
>  2 files changed, 80 insertions(+)<br>
><br>
> diff --git a/Makefile.am b/Makefile.am<br>
> index 485417b..df9a73e 100644<br>
> --- a/Makefile.am<br>
> +++ b/Makefile.am<br>
> @@ -87,6 +87,10 @@ spice_webdavd_LDADD =                \<br>
>         $(PIE_LDFLAGS)          \<br>
>         $(NULL)<br>
><br>
> +if OS_WIN32<br>
> +spice_webdavd_LDADD += -lnetapi32 -lmpr<br>
> +endif<br>
> +<br>
>  deps.txt:<br>
>         $(AM_V_GEN)rpm -qa | grep $(host_os) | sort | unix2dos > $@<br>
><br>
> diff --git a/spice/spice-webdavd.c b/spice/spice-webdavd.c<br>
> index f9c5cf1..3940f1c 100644<br>
> --- a/spice/spice-webdavd.c<br>
> +++ b/spice/spice-webdavd.c<br>
> @@ -737,11 +737,81 @@ open_mux_path (const char *path)<br>
>    mux_queue = output_queue_new (G_OUTPUT_STREAM (mux_ostream));<br>
>  }<br>
><br>
> +#ifdef G_OS_WIN32<br>
> +static gchar<br>
> +get_free_drive_letter(void)<br>
> +{<br>
> +  const guint32 max_mask = 1 << 25;<br>
> +  guint32 drives;<br>
> +  guint32 mask;<br>
> +  gint i;<br>
> +<br>
> +  drives = GetLogicalDrives ();<br>
> +<br>
> +  for (i = 0; i < 26; i++)<br>
> +    {<br>
> +      mask = max_mask >> i;<br>
> +      if ((drives & mask) == 0)<br>
> +        return 'Z' - i;<br>
> +    }<br>
> +<br>
> +  return 0;<br>
> +}<br>
> +<br>
> +static gpointer<br>
> +map_drive(gpointer user_data)<br>
> +{<br>
> +  GCancellable * cancel_map = user_data;<br>
> +  gchar drive_letter;<br>
> +  gchar local_name[3];<br>
> +  gchar remote_name[] = "<a href="http://localhost:9843/" rel="noreferrer" target="_blank">http://localhost:9843/</a>";<br>
> +  NETRESOURCE net_resource;<br>
> +  guint32 retval;<br>
> +  gint i;<br>
> +<br>
> +  for (i = 0; i < 5; ++i)<br>
> +    {<br>
> +      if (g_cancellable_is_cancelled (cancel_map))<br>
> +        return NULL;<br>
> +      else<br>
> +        g_usleep (G_USEC_PER_SEC);<br>
> +    }<br>
<br>
</div></div>It looks like this would fail if the guest is started without client<br>
connected (or not sharing folder).<br></blockquote><div><br></div><div>I'm not sure I follow.<br></div><div>This is supposed to return NULL precisely, if the client is not connected,<br>or not sharing folder. Windows webdavd will loop and call run_service(),<br>until sharing is enabled, which will then NOT cancel this function,<br>and we map the drive.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div><br>
> +<br>
> +  if ((drive_letter = get_free_drive_letter ()) == 0)<br>
> +      g_error ("all drive letters already assigned.");<br>
> +<br>
> +  local_name[0] = drive_letter;<br>
> +  local_name[1] = ':';<br>
> +  local_name[2] = 0;<br>
> +<br>
> +  net_resource.dwType = RESOURCETYPE_DISK;<br>
> +  net_resource.lpLocalName = local_name;<br>
> +  net_resource.lpRemoteName = remote_name;<br>
> +  net_resource.lpProvider = NULL;<br>
> +<br>
> +  retval = WNetAddConnection2 (&net_resource, NULL, NULL, CONNECT_TEMPORARY);<br>
> +<br>
> +  if (retval == NO_ERROR)<br>
> +    g_debug ("map_drive ok");<br>
> +  else if (retval == ERROR_ALREADY_ASSIGNED)<br>
> +    g_debug ("map_drive already asigned");<br>
> +  else<br>
> +    g_error ("map_drive error %d", retval);<br>
> +<br>
> +  return NULL;<br>
> +}<br>
> +#endif<br>
> +<br>
>  static void<br>
>  run_service (void)<br>
>  {<br>
>    g_debug ("Run service");<br>
><br>
> +#ifdef G_OS_WIN32<br>
> +  GCancellable * cancel_map = g_cancellable_new ();<br>
> +  GThread * map_drive_thread = g_thread_new ("map-drive-thread", map_drive, cancel_map);<br>
> +#endif<br>
> +<br>
>    g_socket_service_start (socket_service);<br>
><br>
>    cancel = g_cancellable_new ();<br>
> @@ -775,6 +845,12 @@ run_service (void)<br>
>    g_main_loop_run (loop);<br>
>    g_main_loop_unref (loop);<br>
><br>
> +#ifdef G_OS_WIN32<br>
> +  g_cancellable_cancel (cancel_map);<br>
> +  g_thread_join(map_drive_thread);<br>
> +  g_print ("map-drive-thread joined\n");<br>
> +#endif<br>
> +<br>
>    g_cancellable_cancel (cancel);<br>
><br>
>    g_clear_object (&mux_istream);<br>
> --<br>
> 2.4.3<br>
><br>
</div></div>> _______________________________________________<br>
> Spice-devel mailing list<br>
> <a href="mailto:Spice-devel@lists.freedesktop.org" target="_blank">Spice-devel@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/spice-devel" rel="noreferrer" target="_blank">http://lists.freedesktop.org/mailman/listinfo/spice-devel</a><br>
<span><font color="#888888"><br>
<br>
<br>
--<br>
Marc-André Lureau<br>
</font></span></blockquote></div><br></div><div class="gmail_extra">Lukas Venhoda<br></div></div></div>