Petr Vokac 238799e
diff --git a/src/plugins/apache-httpd/src/client/htext.h b/src/plugins/apache-httpd/src/client/htext.h
Petr Vokac 238799e
index 1303e77e..853a146a 100644
Petr Vokac 238799e
--- a/src/plugins/apache-httpd/src/client/htext.h
Petr Vokac 238799e
+++ b/src/plugins/apache-httpd/src/client/htext.h
Petr Vokac 238799e
@@ -67,6 +67,8 @@ typedef enum
Petr Vokac 238799e
     HTEXTOP_NOHEAD, /* Disable HEAD requests */
Petr Vokac 238799e
 
Petr Vokac 238799e
     HTEXTOP_USE_COPY_FROM_SOURCE, /* Use Copy Source (fetching) instead of Copy Destination (pushing) */
Petr Vokac 238799e
+    HTEXTOP_COPY_DONE, /* If set, called after COPY operation is done */
Petr Vokac 238799e
+    HTEXTOP_COPY_DONE_DATA, /* Additional data to pass to transfer done function */
Petr Vokac 238799e
 
Petr Vokac 238799e
     HTEXTOP_SENTINEL, /* To mark the last one */
Petr Vokac 238799e
 
Petr Vokac 238799e
diff --git a/src/plugins/apache-httpd/src/client/htext_api.c b/src/plugins/apache-httpd/src/client/htext_api.c
Petr Vokac 238799e
index 1c3df75c..201a5e37 100644
Petr Vokac 238799e
--- a/src/plugins/apache-httpd/src/client/htext_api.c
Petr Vokac 238799e
+++ b/src/plugins/apache-httpd/src/client/htext_api.c
Petr Vokac 238799e
@@ -92,6 +92,8 @@ static option_entry option_definitions[] = {
Petr Vokac 238799e
 
Petr Vokac 238799e
     { OT_INT, (option_value) 0 }, /* HTEXTOP_NOHEAD         */
Petr Vokac 238799e
     { OT_INT, (option_value) 0 }, /* HTEXTOP_USE_COPY_FROM_SOURCE */
Petr Vokac 238799e
+    { OT_POINTER, (option_value) NULL }, /* HTEXTOP_COPY_DONE */
Petr Vokac 238799e
+    { OT_POINTER, (option_value) NULL }, /* HTEXTOP_COPY_DONE_DATA */
Petr Vokac 238799e
 };
Petr Vokac 238799e
 
Petr Vokac 238799e
 /**
Petr Vokac 238799e
@@ -156,6 +158,10 @@ void htext_destroy(htext_handle *handle)
Petr Vokac 238799e
     free(handle->error_string);
Petr Vokac 238799e
     free(handle->partial_total);
Petr Vokac 238799e
     free(handle->partial_done);
Petr Vokac 238799e
+    for (i = 0; i < handle->partials; ++i) {
Petr Vokac 238799e
+        free(handle->partial_rconn[i]);
Petr Vokac 238799e
+    }
Petr Vokac 238799e
+    free(handle->partial_rconn);
Petr Vokac 238799e
 
Petr Vokac 238799e
     for (i = 0; i < HTEXTOP_SENTINEL; ++i) {
Petr Vokac 238799e
         if (handle->options[i].type == OT_STRING)
Petr Vokac 238799e
@@ -249,6 +255,7 @@ int htext_perform(htext_handle *handle)
Petr Vokac 238799e
 {
Petr Vokac 238799e
     void* (*performer)(void *);
Petr Vokac 238799e
     const char *performer_str;
Petr Vokac 238799e
+    int i;
Petr Vokac 238799e
 
Petr Vokac 238799e
     /* Check status */
Petr Vokac 238799e
     switch (handle->status) {
Petr Vokac 238799e
@@ -263,9 +270,14 @@ int htext_perform(htext_handle *handle)
Petr Vokac 238799e
     free(handle->error_string);
Petr Vokac 238799e
     free(handle->partial_total);
Petr Vokac 238799e
     free(handle->partial_done);
Petr Vokac 238799e
+    for (i = 0; i < handle->partials; ++i) {
Petr Vokac 238799e
+        free(handle->partial_rconn[i]);
Petr Vokac 238799e
+    }
Petr Vokac 238799e
+    free(handle->partial_rconn);
Petr Vokac 238799e
     handle->error_string = NULL;
Petr Vokac 238799e
     handle->partial_done = NULL;
Petr Vokac 238799e
     handle->partial_total = NULL;
Petr Vokac 238799e
+    handle->partial_rconn = NULL;
Petr Vokac 238799e
     handle->partials = 0;
Petr Vokac 238799e
 
Petr Vokac 238799e
     /* Check we have source and destination */
Petr Vokac 238799e
@@ -326,7 +338,9 @@ int htext_perform(htext_handle *handle)
Petr Vokac 238799e
 
Petr Vokac 238799e
 void htext_abort(htext_handle *handle)
Petr Vokac 238799e
 {
Petr Vokac 238799e
-    /* TODO: Really abort */
Petr Vokac 238799e
+    /* TODO: Transfer is aborted by returning non-zero value from progress
Petr Vokac 238799e
+       function (this doesn't happen immediately and with curl easy interface
Petr Vokac 238799e
+       there is no better option except closing directly transfer socket) */
Petr Vokac 238799e
     handle->status = HTEXTS_ABORTED;
Petr Vokac 238799e
 }
Petr Vokac 238799e
 
Petr Vokac 238799e
diff --git a/src/plugins/apache-httpd/src/client/htext_common.c b/src/plugins/apache-httpd/src/client/htext_common.c
Petr Vokac 238799e
index 34a28353..219988dc 100644
Petr Vokac 238799e
--- a/src/plugins/apache-httpd/src/client/htext_common.c
Petr Vokac 238799e
+++ b/src/plugins/apache-httpd/src/client/htext_common.c
Petr Vokac 238799e
@@ -40,8 +40,6 @@ void htext_partial_clean(htext_chunk *p)
Petr Vokac 238799e
         curl_easy_cleanup(p->curl);
Petr Vokac 238799e
     if (p->fd)
Petr Vokac 238799e
         GETIO(p->handle) ->close(p->fd);
Petr Vokac 238799e
-    if (p->chunk_rconn && *(p->chunk_rconn))
Petr Vokac 238799e
-        free(*(p->chunk_rconn));
Petr Vokac 238799e
     if (p->error_string)
Petr Vokac 238799e
         free(p->error_string);
Petr Vokac 238799e
     if (p->http_response)
Petr Vokac 238799e
@@ -219,28 +217,37 @@ int htext_progress_callback(void *pp, curl_off_t dltotal, curl_off_t dlnow,
Petr Vokac 238799e
         *(partial->chunk_done) = dlnow;
Petr Vokac 238799e
     }
Petr Vokac 238799e
 
Petr Vokac 238799e
-    CURLcode res = CURLE_OK;
Petr Vokac 238799e
-    char *ip = NULL;
Petr Vokac 238799e
-    long port = 0;
Petr Vokac 238799e
-
Petr Vokac 238799e
-    if (res == CURLE_OK)
Petr Vokac 238799e
-        res = curl_easy_getinfo(partial->curl, CURLINFO_PRIMARY_IP, &ip);
Petr Vokac 238799e
-    if (res == CURLE_OK)
Petr Vokac 238799e
-        res = curl_easy_getinfo(partial->curl, CURLINFO_PRIMARY_PORT, &port);
Petr Vokac 238799e
-    if (res == CURLE_OK && ip) {
Petr Vokac 238799e
-        int len = strlen(ip)+15;
Petr Vokac 238799e
-        char *rconn = malloc(len);
Petr Vokac 238799e
-        if (strchr(ip, ':')) {
Petr Vokac 238799e
-            snprintf(rconn, len, "tcp:[%s]:%ld", ip, port);
Petr Vokac 238799e
-        } else {
Petr Vokac 238799e
-            snprintf(rconn, len, "tcp:%s:%ld", ip, port);
Petr Vokac 238799e
+    /* Add remote connection only after real data transfer starts
Petr Vokac 238799e
+       otherwise ip:port info could come previous (headnode) connection */
Petr Vokac 238799e
+    if (dltotal > 0 || dlnow > 0 || ultotal > 0 || ulnow > 0) {
Petr Vokac 238799e
+        CURLcode res = CURLE_OK;
Petr Vokac 238799e
+        char *ip = NULL;
Petr Vokac 238799e
+        long port = 0;
Petr Vokac 238799e
+
Petr Vokac 238799e
+	if (res == CURLE_OK)
Petr Vokac 238799e
+            res = curl_easy_getinfo(partial->curl, CURLINFO_PRIMARY_IP, &ip);
Petr Vokac 238799e
+        if (res == CURLE_OK)
Petr Vokac 238799e
+            res = curl_easy_getinfo(partial->curl, CURLINFO_PRIMARY_PORT, &port);
Petr Vokac 238799e
+
Petr Vokac 238799e
+	if (res == CURLE_OK && ip && port) {
Petr Vokac 238799e
+            char rconn[HTEXT_PERF_MARKER_MAX_RCONN_SIZE];
Petr Vokac 238799e
+            if (strchr(ip, ':')) {
Petr Vokac 238799e
+                snprintf(rconn, sizeof(rconn), "tcp:[%s]:%ld", ip, port);
Petr Vokac 238799e
+            } else {
Petr Vokac 238799e
+                snprintf(rconn, sizeof(rconn), "tcp:%s:%ld", ip, port);
Petr Vokac 238799e
+            }
Petr Vokac 238799e
+            htext_log(partial->handle, "connection %s, download %ld/%ld, upload %ld/%ld", rconn, dlnow, dltotal, ulnow, ultotal);
Petr Vokac 238799e
+            if (!*(partial->chunk_rconn))
Petr Vokac 238799e
+                *(partial->chunk_rconn) = calloc(sizeof(char), HTEXT_PERF_MARKER_MAX_RCONN_SIZE);
Petr Vokac 238799e
+            if (strcmp(*(partial->chunk_rconn), rconn))
Petr Vokac 238799e
+                strcpy(*(partial->chunk_rconn), rconn);
Petr Vokac 238799e
         }
Petr Vokac 238799e
-        htext_log(partial->handle, "connection %s, download %ld/%ld, upload %ld/%ld", rconn, dlnow, dltotal, ulnow, ultotal);
Petr Vokac 238799e
-        char *tmp = *(partial->chunk_rconn);
Petr Vokac 238799e
-        *(partial->chunk_rconn) = rconn;
Petr Vokac 238799e
-        if (tmp) free(tmp);
Petr Vokac 238799e
     }
Petr Vokac 238799e
 
Petr Vokac 238799e
+    /* Let curl abort terminated transfer (doesn't happen immediately) */
Petr Vokac 238799e
+    if (partial->handle->status == HTEXTS_ABORTED)
Petr Vokac 238799e
+        return 1;
Petr Vokac 238799e
+
Petr Vokac 238799e
     return 0;
Petr Vokac 238799e
 }
Petr Vokac 238799e
 
Petr Vokac 238799e
diff --git a/src/plugins/apache-httpd/src/client/htext_copy.c b/src/plugins/apache-httpd/src/client/htext_copy.c
Petr Vokac 238799e
index 88c4aacd..0be2f969 100644
Petr Vokac 238799e
--- a/src/plugins/apache-httpd/src/client/htext_copy.c
Petr Vokac 238799e
+++ b/src/plugins/apache-httpd/src/client/htext_copy.c
Petr Vokac 238799e
@@ -83,6 +83,7 @@ static size_t htext_copy_write_callback(char *buffer, size_t size, size_t nmemb,
Petr Vokac 238799e
             memset(perf_data, 0, sizeof(*perf_data));
Petr Vokac 238799e
             perf_data->index = -1;
Petr Vokac 238799e
             perf_data->transferred = -1;
Petr Vokac 238799e
+            perf_data->rconn[0] = '\0';
Petr Vokac 238799e
         }
Petr Vokac 238799e
         else if (strncasecmp("Timestamp:", p, 10) == 0)
Petr Vokac 238799e
         {
Petr Vokac 238799e
@@ -94,15 +95,17 @@ static size_t htext_copy_write_callback(char *buffer, size_t size, size_t nmemb,
Petr Vokac 238799e
         }
Petr Vokac 238799e
         else if (strncasecmp("Stripe Bytes Transferred:", p, 25) == 0)
Petr Vokac 238799e
         {
Petr Vokac 238799e
-            perf_data->transferred = atol(p + 26);
Petr Vokac 238799e
+            perf_data->transferred = atol(p + 25);
Petr Vokac 238799e
         }
Petr Vokac 238799e
         else if (strncasecmp("Total Stripe Count:", p, 19) == 0)
Petr Vokac 238799e
         {
Petr Vokac 238799e
-            perf_data->count = atoi(p + 20);
Petr Vokac 238799e
+            perf_data->count = atoi(p + 19);
Petr Vokac 238799e
         }
Petr Vokac 238799e
         else if (strncasecmp("RemoteConnections:", p, 18) == 0)
Petr Vokac 238799e
         {
Petr Vokac 238799e
-            strcpy(perf_data->rconn, p + 19);
Petr Vokac 238799e
+            char *c = p+18;
Petr Vokac 238799e
+            while (isspace(*c)) c++;
Petr Vokac 238799e
+            snprintf(perf_data->rconn, sizeof(perf_data->rconn), "%s", c);
Petr Vokac 238799e
         }
Petr Vokac 238799e
         // skip unused dCache perf markers
Petr Vokac 238799e
         else if (strncasecmp("State:", p, 6) == 0) {}
Petr Vokac 238799e
@@ -137,8 +140,12 @@ static size_t htext_copy_write_callback(char *buffer, size_t size, size_t nmemb,
Petr Vokac 238799e
 
Petr Vokac 238799e
                 handle->partial_done[perf_data->index] = perf_data->transferred;
Petr Vokac 238799e
                 handle->partial_total[perf_data->index] = 0;
Petr Vokac 238799e
-                handle->partial_rconn[perf_data->index] = perf_data->rconn[0] != '\0' ? strdup(perf_data->rconn) : NULL;
Petr Vokac 238799e
-
Petr Vokac 238799e
+                if (perf_data->rconn[0] != '\0') {
Petr Vokac 238799e
+                    if (!handle->partial_rconn[perf_data->index])
Petr Vokac 238799e
+                        handle->partial_rconn[perf_data->index] = calloc(sizeof(char), HTEXT_PERF_MARKER_MAX_RCONN_SIZE);
Petr Vokac 238799e
+                    if (strcmp(handle->partial_rconn[perf_data->index], perf_data->rconn))
Petr Vokac 238799e
+                        strcpy(handle->partial_rconn[perf_data->index], perf_data->rconn);
Petr Vokac 238799e
+                }
Petr Vokac 238799e
             }
Petr Vokac 238799e
             
Petr Vokac 238799e
         }
Petr Vokac 238799e
@@ -257,8 +264,15 @@ void *htext_copy_method(void *h)
Petr Vokac 238799e
 
Petr Vokac 238799e
     handle->http_status = control.http_status;
Petr Vokac 238799e
 
Petr Vokac 238799e
+    /* Call transfer done callback */
Petr Vokac 238799e
+    if (GETPTR(handle, HTEXTOP_COPY_DONE)) {
Petr Vokac 238799e
+        void (*copy_done)(htext_handle *, int, void *) = GETPTR(handle, HTEXTOP_COPY_DONE);
Petr Vokac 238799e
+        copy_done(handle, handle->status, GETPTR(handle, HTEXTOP_COPY_DONE_DATA));
Petr Vokac 238799e
+    }
Petr Vokac 238799e
+
Petr Vokac 238799e
     /* Clean up */
Petr Vokac 238799e
     htext_partial_clean(&control);
Petr Vokac 238799e
     curl_easy_cleanup(curl);
Petr Vokac 238799e
+
Petr Vokac 238799e
     return NULL ;
Petr Vokac 238799e
 }
Petr Vokac 238799e
diff --git a/src/plugins/apache-httpd/src/client/htext_get.c b/src/plugins/apache-httpd/src/client/htext_get.c
Petr Vokac 238799e
index 0fb49bde..ae9b686b 100644
Petr Vokac 238799e
--- a/src/plugins/apache-httpd/src/client/htext_get.c
Petr Vokac 238799e
+++ b/src/plugins/apache-httpd/src/client/htext_get.c
Petr Vokac 238799e
@@ -276,6 +276,13 @@ void *htext_get_method(void *h)
Petr Vokac 238799e
         handle->status = HTEXTS_SUCCEEDED;
Petr Vokac 238799e
     }
Petr Vokac 238799e
 
Petr Vokac 238799e
+    /* Call transfer done callback */
Petr Vokac 238799e
+    if (GETPTR(handle, HTEXTOP_COPY_DONE)) {
Petr Vokac 238799e
+        void (*copy_done)(htext_handle *, int, void *) = GETPTR(handle, HTEXTOP_COPY_DONE);
Petr Vokac 238799e
+        copy_done(handle, handle->status, GETPTR(handle, HTEXTOP_COPY_DONE_DATA));
Petr Vokac 238799e
+    }
Petr Vokac 238799e
+
Petr Vokac 238799e
+    /* Clean up */
Petr Vokac 238799e
     curl_easy_cleanup(curl);
Petr Vokac 238799e
     free(partial_array);
Petr Vokac 238799e
 
Petr Vokac 238799e
diff --git a/src/plugins/apache-httpd/src/client/htext_private.h b/src/plugins/apache-httpd/src/client/htext_private.h
Petr Vokac 238799e
index 0a406df7..b4369c1e 100644
Petr Vokac 238799e
--- a/src/plugins/apache-httpd/src/client/htext_private.h
Petr Vokac 238799e
+++ b/src/plugins/apache-httpd/src/client/htext_private.h
Petr Vokac 238799e
@@ -113,13 +113,14 @@ typedef struct htext_chunk htext_chunk;
Petr Vokac 238799e
  * and unprocessed last line from input data
Petr Vokac 238799e
  */
Petr Vokac 238799e
 #define HTEXT_PERF_MARKER_MAX_LINE_SIZE 1024
Petr Vokac 238799e
+#define HTEXT_PERF_MARKER_MAX_RCONN_SIZE 256
Petr Vokac 238799e
 struct htext_perf_marker_parsed_data
Petr Vokac 238799e
 {
Petr Vokac 238799e
     time_t latest; /* Timestamp for received data */
Petr Vokac 238799e
     int index; /* Stripe index */
Petr Vokac 238799e
     off_t transferred; /* Stripe bytes transferred */
Petr Vokac 238799e
     int count; /* Total stripe count */
Petr Vokac 238799e
-    char rconn[HTEXT_PERF_MARKER_MAX_LINE_SIZE]; /* Remote connections */
Petr Vokac 238799e
+    char rconn[HTEXT_PERF_MARKER_MAX_RCONN_SIZE]; /* Remote connections */
Petr Vokac 238799e
 
Petr Vokac 238799e
     char remaining[HTEXT_PERF_MARKER_MAX_LINE_SIZE]; /* Remaining input data from unterminated last line */
Petr Vokac 238799e
 };
Petr Vokac 238799e
diff --git a/src/plugins/apache-httpd/src/client/htext_put.c b/src/plugins/apache-httpd/src/client/htext_put.c
Petr Vokac 238799e
index 0c3e4c1d..94d8781a 100644
Petr Vokac 238799e
--- a/src/plugins/apache-httpd/src/client/htext_put.c
Petr Vokac 238799e
+++ b/src/plugins/apache-httpd/src/client/htext_put.c
Petr Vokac 238799e
@@ -377,6 +377,12 @@ void *htext_put_method(void *h)
Petr Vokac 238799e
         handle->status = HTEXTS_SUCCEEDED;
Petr Vokac 238799e
     }
Petr Vokac 238799e
 
Petr Vokac 238799e
+    /* Call transfer done callback */
Petr Vokac 238799e
+    if (GETPTR(handle, HTEXTOP_COPY_DONE)) {
Petr Vokac 238799e
+        void (*copy_done)(htext_handle *, int, void *) = GETPTR(handle, HTEXTOP_COPY_DONE);
Petr Vokac 238799e
+        copy_done(handle, handle->status, GETPTR(handle, HTEXTOP_COPY_DONE_DATA));
Petr Vokac 238799e
+    }
Petr Vokac 238799e
+
Petr Vokac 238799e
     curl_easy_cleanup(curl);
Petr Vokac 238799e
     free(partial_array);
Petr Vokac 238799e
 
Petr Vokac 238799e
diff --git a/src/plugins/apache-httpd/src/mod_lcgdm_disk/copy.c b/src/plugins/apache-httpd/src/mod_lcgdm_disk/copy.c
Petr Vokac 238799e
index dd586da6..cdc22c30 100644
Petr Vokac 238799e
--- a/src/plugins/apache-httpd/src/mod_lcgdm_disk/copy.c
Petr Vokac 238799e
+++ b/src/plugins/apache-httpd/src/mod_lcgdm_disk/copy.c
Petr Vokac 238799e
@@ -42,6 +42,8 @@ typedef struct
Petr Vokac 238799e
     request_rec *request;
Petr Vokac 238799e
     const char *source;
Petr Vokac 238799e
     const char *destination;
Petr Vokac 238799e
+    pthread_mutex_t *done_lock;
Petr Vokac 238799e
+    pthread_cond_t *done_cond;
Petr Vokac 238799e
 } dav_disk_copy_data;
Petr Vokac 238799e
 
Petr Vokac 238799e
 /* Custom I/O handler */
Petr Vokac 238799e
@@ -191,6 +193,30 @@ static void dav_disk_copy_log(htext_handle *handle, HTEXT_LOG_TYPE type,
Petr Vokac 238799e
     }
Petr Vokac 238799e
 }
Petr Vokac 238799e
 
Petr Vokac 238799e
+/**
Petr Vokac 238799e
+ * Called by htext when transfer is done
Petr Vokac 238799e
+ * @param handle The handle that triggers the call
Petr Vokac 238799e
+ * @param status The size of the message (it might not be NULL terminated)
Petr Vokac 238799e
+ * @param ud     User defined data
Petr Vokac 238799e
+ */
Petr Vokac 238799e
+static void dav_disk_copy_done(htext_handle *handle, int status, void *ud)
Petr Vokac 238799e
+{
Petr Vokac 238799e
+    dav_disk_copy_data *ddc = (dav_disk_copy_data*) ud;
Petr Vokac 238799e
+
Petr Vokac 238799e
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ddc->request,
Petr Vokac 238799e
+            "Remote copy done (%d): %s => %s status %i",
Petr Vokac 238799e
+            htext_http_code(handle), ddc->source, ddc->destination, status);
Petr Vokac 238799e
+
Petr Vokac 238799e
+    // send signal to finish perf marker loop
Petr Vokac 238799e
+ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ddc->request, "EEEE Remote copy done (%d): %s => %s status %i", htext_http_code(handle), ddc->source, ddc->destination, status);
Petr Vokac 238799e
+    pthread_mutex_lock(ddc->done_lock);
Petr Vokac 238799e
+ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ddc->request, "EEEE Remote copy done (%d): %s => %s status %i", htext_http_code(handle), ddc->source, ddc->destination, status);
Petr Vokac 238799e
+    pthread_cond_signal(ddc->done_cond);
Petr Vokac 238799e
+ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ddc->request, "EEEE Remote copy done (%d): %s => %s status %i", htext_http_code(handle), ddc->source, ddc->destination, status);
Petr Vokac 238799e
+    pthread_mutex_unlock(ddc->done_lock);
Petr Vokac 238799e
+ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ddc->request, "EEEE Remote copy done (%d): %s => %s status %i", htext_http_code(handle), ddc->source, ddc->destination, status);
Petr Vokac 238799e
+}
Petr Vokac 238799e
+
Petr Vokac 238799e
 /**
Petr Vokac 238799e
  * Generates and sends the performance clients following GridFTP format
Petr Vokac 238799e
  * http://www.ogf.org/documents/GFD.20.pdf (Appendix II), skipping the
Petr Vokac 238799e
@@ -201,14 +223,14 @@ static void dav_disk_send_performance_markers(dav_disk_copy_data *ddc, size_t n,
Petr Vokac 238799e
 {
Petr Vokac 238799e
     (void) total;
Petr Vokac 238799e
 
Petr Vokac 238799e
-    char buf[80];
Petr Vokac 238799e
+    char buf[256+2]; // HTEXT_PERF_MARKER_MAX_RCONN_SIZE+2
Petr Vokac 238799e
     time_t timestamp = time(NULL );
Petr Vokac 238799e
     size_t i;
Petr Vokac 238799e
 
Petr Vokac 238799e
     for (i = 0; i < n; ++i) {
Petr Vokac 238799e
         buf[0] = '\0';
Petr Vokac 238799e
         if (rconn && rconn[i]) {
Petr Vokac 238799e
-            snprintf(buf, 78, "\tRemoteConnections: %s", rconn[i]);
Petr Vokac 238799e
+            snprintf(buf, sizeof(buf)-2, "\tRemoteConnections: %s", rconn[i]);
Petr Vokac 238799e
             strcat(buf, "\n"); // we reserved space for endl
Petr Vokac 238799e
         }
Petr Vokac 238799e
         apr_brigade_printf(ddc->brigade, ap_filter_flush, ddc->output,
Petr Vokac 238799e
@@ -228,52 +250,81 @@ static void dav_disk_send_performance_markers(dav_disk_copy_data *ddc, size_t n,
Petr Vokac 238799e
 static dav_error *dav_disk_pool_and_feedback(htext_handle *handle,
Petr Vokac 238799e
         dav_disk_copy_data *ddc)
Petr Vokac 238799e
 {
Petr Vokac 238799e
-    int wait, status;
Petr Vokac 238799e
+    int status, interval = 1, done = 0;
Petr Vokac 238799e
     dav_error *error = NULL;
Petr Vokac 238799e
     const char *error_string;
Petr Vokac 238799e
 
Petr Vokac 238799e
-    do {
Petr Vokac 238799e
-        size_t *total, *done, n, i;
Petr Vokac 238799e
-        size_t globalDone, globalTotal;
Petr Vokac 238799e
-        char **rconn;
Petr Vokac 238799e
+    pthread_mutex_lock(ddc->done_lock); 
Petr Vokac 238799e
 
Petr Vokac 238799e
+    do {
Petr Vokac 238799e
         status = htext_status(handle);
Petr Vokac 238799e
-        switch (status) {
Petr Vokac 238799e
-            case HTEXTS_SUCCEEDED:
Petr Vokac 238799e
-            case HTEXTS_FAILED:
Petr Vokac 238799e
-            case HTEXTS_ABORTED:
Petr Vokac 238799e
-                wait = 0;
Petr Vokac 238799e
-                break;
Petr Vokac 238799e
-            default:
Petr Vokac 238799e
-                /* In the first go we need to set the reply */
Petr Vokac 238799e
-                if (ddc->request->status == 0) {
Petr Vokac 238799e
-                    ddc->request->status = HTTP_ACCEPTED;
Petr Vokac 238799e
-                    ap_set_content_type(ddc->request, "text/plain");
Petr Vokac 238799e
-                }
Petr Vokac 238799e
-                /* Print progress */
Petr Vokac 238799e
-                htext_progress(handle, &n, &total, &done, &rconn);
Petr Vokac 238799e
-                globalDone = globalTotal = 0;
Petr Vokac 238799e
-                for (i = 0; i < n; ++i) {
Petr Vokac 238799e
-                    globalDone += done[i];
Petr Vokac 238799e
-                    globalTotal += total[i];
Petr Vokac 238799e
-                }
Petr Vokac 238799e
-
Petr Vokac 238799e
-                dav_disk_send_performance_markers(ddc, n, total, done, rconn);
Petr Vokac 238799e
-
Petr Vokac 238799e
-                if (ap_fflush(ddc->output, ddc->brigade) == APR_SUCCESS) {
Petr Vokac 238799e
-                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ddc->request,
Petr Vokac 238799e
-                            "COPY '%s' %lu/%lu", ddc->request->uri,
Petr Vokac 238799e
-                            (unsigned long) globalDone,
Petr Vokac 238799e
-                            (unsigned long) globalTotal);
Petr Vokac 238799e
-                    wait = 1;
Petr Vokac 238799e
-                    sleep(1);
Petr Vokac 238799e
-                }
Petr Vokac 238799e
-                else {
Petr Vokac 238799e
-                    wait = 0;
Petr Vokac 238799e
-                    htext_abort(handle);
Petr Vokac 238799e
-                }
Petr Vokac 238799e
+
Petr Vokac 238799e
+        if (status == HTEXTS_SUCCEEDED || status == HTEXTS_FAILED || status == HTEXTS_ABORTED) {
Petr Vokac 238799e
+            done = 1;
Petr Vokac 238799e
+        }
Petr Vokac 238799e
+        else {
Petr Vokac 238799e
+            struct timespec ts;
Petr Vokac 238799e
+            clock_gettime(CLOCK_REALTIME, &ts);
Petr Vokac 238799e
+            ts.tv_sec += interval;
Petr Vokac 238799e
+            interval = 5; // 5s between perf markers except for first one
Petr Vokac 238799e
+
Petr Vokac 238799e
+            int rc = pthread_cond_timedwait(ddc->done_cond, ddc->done_lock, &ts);
Petr Vokac 238799e
+            if (rc == 0) {
Petr Vokac 238799e
+                // transfer done, continue to get new status
Petr Vokac 238799e
+                continue;
Petr Vokac 238799e
+            }
Petr Vokac 238799e
+            else if (rc == ETIMEDOUT) {
Petr Vokac 238799e
+                // ongoing transfer, reached time to print new perfmarker
Petr Vokac 238799e
+            }
Petr Vokac 238799e
+            else {
Petr Vokac 238799e
+                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ddc->request,
Petr Vokac 238799e
+                        "Waiting for perf marker condition failed for COPY '%s' rc %i",
Petr Vokac 238799e
+                        ddc->request->uri, rc);
Petr Vokac 238799e
+                htext_abort(handle);
Petr Vokac 238799e
+                continue;
Petr Vokac 238799e
+            }
Petr Vokac 238799e
+        }
Petr Vokac 238799e
+
Petr Vokac 238799e
+        /* Always write last performance marker and in defined intervals */
Petr Vokac 238799e
+        {
Petr Vokac 238799e
+            size_t *total, *done, n, i;
Petr Vokac 238799e
+            size_t globalDone, globalTotal;
Petr Vokac 238799e
+            char **rconn;
Petr Vokac 238799e
+
Petr Vokac 238799e
+            /* In the first go we need to set the reply */
Petr Vokac 238799e
+            if (ddc->request->status == 0) {
Petr Vokac 238799e
+                ddc->request->status = HTTP_ACCEPTED;
Petr Vokac 238799e
+                ap_set_content_type(ddc->request, "text/plain");
Petr Vokac 238799e
+            }
Petr Vokac 238799e
+            /* Print progress */
Petr Vokac 238799e
+            htext_progress(handle, &n, &total, &done, &rconn);
Petr Vokac 238799e
+            dav_disk_send_performance_markers(ddc, n, total, done, rconn);
Petr Vokac 238799e
+
Petr Vokac 238799e
+            globalDone = globalTotal = 0;
Petr Vokac 238799e
+            for (i = 0; i < n; ++i) {
Petr Vokac 238799e
+                globalDone += done[i];
Petr Vokac 238799e
+                globalTotal += total[i];
Petr Vokac 238799e
+            }
Petr Vokac 238799e
+
Petr Vokac 238799e
+            if (ap_fflush(ddc->output, ddc->brigade) == APR_SUCCESS) {
Petr Vokac 238799e
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, ddc->request,
Petr Vokac 238799e
+                        "COPY '%s' %lu/%lu", ddc->request->uri,
Petr Vokac 238799e
+                        (unsigned long) globalDone,
Petr Vokac 238799e
+                        (unsigned long) globalTotal);
Petr Vokac 238799e
+            }
Petr Vokac 238799e
+            else {
Petr Vokac 238799e
+                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, ddc->request,
Petr Vokac 238799e
+                        "Failed to send perf marker for COPY '%s' %lu/%lu",
Petr Vokac 238799e
+                        ddc->request->uri,
Petr Vokac 238799e
+                        (unsigned long) globalDone,
Petr Vokac 238799e
+                        (unsigned long) globalTotal);
Petr Vokac 238799e
+                htext_abort(handle);
Petr Vokac 238799e
+            }
Petr Vokac 238799e
         }
Petr Vokac 238799e
-    } while (wait);
Petr Vokac 238799e
+
Petr Vokac 238799e
+    } while (!done);
Petr Vokac 238799e
+
Petr Vokac 238799e
+    pthread_mutex_unlock(ddc->done_lock);
Petr Vokac 238799e
 
Petr Vokac 238799e
     error_string = htext_error_string(handle);
Petr Vokac 238799e
     switch (status) {
Petr Vokac 238799e
@@ -439,6 +490,8 @@ static dav_error *dav_disk_generic_copy(const dav_resource* res, const char* upr
Petr Vokac 238799e
     dav_disk_copy_data ddc;
Petr Vokac 238799e
     request_rec* req = res->info->request;
Petr Vokac 238799e
     dav_disk_dir_conf* d_conf = res->info->d_conf;
Petr Vokac 238799e
+    pthread_mutex_t done_lock;
Petr Vokac 238799e
+    pthread_cond_t done_cond;
Petr Vokac 238799e
 
Petr Vokac 238799e
     int oldcancel;
Petr Vokac 238799e
     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldcancel);
Petr Vokac 238799e
@@ -475,6 +528,9 @@ static dav_error *dav_disk_generic_copy(const dav_resource* res, const char* upr
Petr Vokac 238799e
     htext_setopt(handle, HTEXTOP_LOW_SPEED_TIME, d_conf->low_speed_time);
Petr Vokac 238799e
     htext_setopt(handle, HTEXTOP_LOW_SPEED_LIMIT, d_conf->low_speed_limit);
Petr Vokac 238799e
 
Petr Vokac 238799e
+    htext_setopt(handle, HTEXTOP_COPY_DONE, dav_disk_copy_done);
Petr Vokac 238799e
+    htext_setopt(handle, HTEXTOP_COPY_DONE_DATA, &ddc;;
Petr Vokac 238799e
+
Petr Vokac 238799e
     htext_setopt(handle, HTEXTOP_LOGCALLBACK, dav_disk_copy_log);
Petr Vokac 238799e
     htext_setopt(handle, HTEXTOP_LOGCALLBACK_DATA, &ddc;;
Petr Vokac 238799e
     htext_setopt(handle, HTEXTOP_VERBOSITY, 2);
Petr Vokac 238799e
@@ -486,13 +542,23 @@ static dav_error *dav_disk_generic_copy(const dav_resource* res, const char* upr
Petr Vokac 238799e
     ddc.request = req;
Petr Vokac 238799e
     ddc.source = src;
Petr Vokac 238799e
     ddc.destination = dst;
Petr Vokac 238799e
+    ddc.done_lock = &done_lock;
Petr Vokac 238799e
+    ddc.done_cond = &done_cond;
Petr Vokac 238799e
+
Petr Vokac 238799e
+    pthread_mutex_init(&done_lock, NULL);
Petr Vokac 238799e
+    pthread_cond_init(&done_cond, NULL);
Petr Vokac 238799e
 
Petr Vokac 238799e
     /* Run */
Petr Vokac 238799e
     if (htext_perform(handle) != 0) {
Petr Vokac 238799e
         error = dav_shared_new_error(req, NULL,
Petr Vokac 238799e
                 HTTP_INTERNAL_SERVER_ERROR, "Could not perform the action: %s",
Petr Vokac 238799e
                 htext_error_string(handle));
Petr Vokac 238799e
+
Petr Vokac 238799e
+        pthread_cond_destroy(&done_cond);
Petr Vokac 238799e
+        pthread_mutex_destroy(&done_lock);
Petr Vokac 238799e
+
Petr Vokac 238799e
         htext_destroy(handle);
Petr Vokac 238799e
+
Petr Vokac 238799e
         return error;
Petr Vokac 238799e
     }
Petr Vokac 238799e
 
Petr Vokac 238799e
@@ -504,6 +570,9 @@ static dav_error *dav_disk_generic_copy(const dav_resource* res, const char* upr
Petr Vokac 238799e
 
Petr Vokac 238799e
     /* Finish */
Petr Vokac 238799e
     htext_destroy(handle);
Petr Vokac 238799e
+
Petr Vokac 238799e
+    pthread_cond_destroy(&done_cond);
Petr Vokac 238799e
+    pthread_mutex_destroy(&done_lock);
Petr Vokac 238799e
     
Petr Vokac 238799e
     if (!error) {
Petr Vokac 238799e
         bkt = apr_bucket_eos_create(ddc.output->c->bucket_alloc);