--- src/networks/donkey/donkeyClient.ml	2007-01-07 23:38:52.807340416 +0100
+++ src/networks/donkey/donkeyClient.ml	2007-01-08 01:18:43.566606576 +0100
@@ -248,24 +248,7 @@
       c.client_source.DonkeySources.source_sock <- NoConnection
   | Connection sock ->
       (try
-    let log_print cc = lprintf_nl "Client[%d] %s disconnected, connected %s%s%s"
-      (client_num c) (full_client_identifier c)
-      (Date.time_to_string (last_time () - c.client_connect_time) "verbose")
-      (if c.client_total_uploaded > 0L then
-        Printf.sprintf ", send %s (%s)%s"
-          (size_of_int64 c.client_session_uploaded)
-          (size_of_int64 c.client_total_uploaded)
-          (match client_upload (as_client c) with | None -> ""
-           | Some f -> " of " ^ (CommonFile.file_best_name f)) else "")
-      (if c.client_total_downloaded > 0L then
-        Printf.sprintf ", rec %s (%s)"
-          (size_of_int64 c.client_session_downloaded)
-          (size_of_int64 c.client_total_downloaded) else "")
-    in
-    if c.client_debug ||
-      (!verbose && (c.client_session_uploaded > 0L || c.client_session_downloaded > 0L)) then
-      log_print c;
-
+          DonkeyOneFile.remove_client_slot c;
           c.client_comp <- None;
           (try if c.client_checked then count_seen c with _ -> ());
           (try if !!log_clients_on_console && c.client_name <> "" then 
@@ -273,14 +256,11 @@
           c.client_connect_time <- 0;
           (try Hashtbl.remove connected_clients c.client_md4 with _ -> ());
           (try CommonUploads.remove_pending_slot (as_client c) with _ -> ());
-          set_client_has_a_slot (as_client c) NoSlot;
-(*          connection_failed c.client_connection_control; *)
           (try TcpBufferedSocket.close sock reason with _ -> ());
 
 (* Remove the Connected and NoLimit tags *)
           set_client_type c (client_type c
               land (lnot (client_initialized_tag lor client_nolimit_tag)));
-(*          c.client_chunks <- [||];*)
           c.client_source.DonkeySources.source_sock <- NoConnection;
           save_join_queue c;
           c.client_slot <- SlotNotAsked;
@@ -293,23 +273,10 @@
           )
           files;    
           c.client_file_queue <- [];  
-          if c.client_upload != None then CommonUploads.refill_upload_slots ();
+          c.client_session_downloaded <- 0L;
         
         with e -> lprintf_nl "Exception %s in disconnect_client"
               (Printexc2.to_string e));
-(*      lprintf "Client %d to source:" (client_num c);
-      List.iter (fun r ->
-                lprint_char (
-                  match r.request_result with
-                  | File_chunk ->      'C'
-                  | File_upload ->     'U'
-                  | File_not_found ->  '-'
-                  | File_found ->      '+'
-                  | File_possible ->   '?'
-                  | File_expected ->   '!'
-                  | File_new_source -> 'n'
-                )) c.client_files;      
-      lprintf "\n"; *)
       set_client_disconnected c reason;
       DonkeySources.source_disconnected c.client_source
   
@@ -448,7 +415,13 @@
         
   
 let new_chunk up begin_pos end_pos =
-  if begin_pos <> end_pos then
+  let req_size = end_pos -- begin_pos in
+  let req_location = (begin_pos ++ end_pos) // (2L ** block_size) in
+  if !verbose_upload then
+    lprintf_nl "new block: (%Ld,%Ld) size %Ld chunk #%Ld" begin_pos end_pos req_size req_location;
+  if (req_size < Int64.zero) || (req_size > zone_size) || ((up.up_current <> req_location) && (req_size <> Int64.zero)) then
+    up.up_finish <- true;
+  if ((not up.up_finish) || (not !!upload_complete_chunks)) && (req_size > Int64.zero) && (req_size <= zone_size) then
     let chunk = (begin_pos, end_pos) in
     (* the zone requested is already "in the pipe" *)
     if not (List.mem chunk up.up_flying_chunks) then
@@ -1419,7 +1392,7 @@
 	     | Some f -> CommonFile.file_best_name f);
 (*      end *)
   
-  | M.CloseSlotReq _ ->
+  | M.OutOfPartsReq _ ->
       set_client_state c (Connected 0);
       begin
         match c.client_download with
@@ -1430,6 +1403,7 @@
             CommonSwarming.clear_uploader_ranges up
       end;
 (*      DonkeyOneFile.clean_current_download c; *)
+      c.client_session_downloaded <- 0L;
       c.client_slot <- SlotNotAsked;
 (* OK, the slot is closed, but what should we do now ????? *)
       begin
@@ -1437,7 +1411,7 @@
           [] -> ()
         | _ -> 
             if !verbose_download then
-                lprintf_nl "CloseSlotReq"; 
+                lprintf_nl "OutOfPartsReq"; 
             DonkeyOneFile.request_slot c;
             set_rtimeout sock !!queued_timeout;
       end
@@ -2026,16 +2000,16 @@
   | M.QueryBlocReq t when !CommonUploads.has_upload = 0 &&
     client_has_a_slot (as_client c) ->
       
-      if !verbose_upload then
-          lprintf_nl "donkeyClient: uploader %s ask for block" (full_client_identifier c);
-      
       let module Q = M.QueryBloc in
       let file = find_file  t.Q.md4 in
+
+      if !verbose_upload then lprintf_nl "donkeyClient: uploader %s asks for %s"
+            (full_client_identifier c) (file_best_name file);
+
       let prio = (file_priority file) in
       let client_upload_lifetime = ref ((max 0 !!upload_lifetime) * 60) in
-      begin
         
-        if !!dynamic_upload_lifetime
+      if !!dynamic_upload_lifetime && not !!upload_complete_chunks
             && c.client_session_uploaded > c.client_session_downloaded
             && c.client_session_uploaded > Int64.of_int !!dynamic_upload_threshold ** zone_size
         then
@@ -2043,13 +2017,20 @@
           Int64.to_int 
             (Int64.of_int !client_upload_lifetime 
               ** c.client_session_downloaded // c.client_session_uploaded);
-        if last_time() > c.client_connect_time + 
-            !client_upload_lifetime + 5 * prio then
-          begin
-
-(* And what happens if we were downloading from this client also ? *)
             
-            disconnect_client c (Closed_for_error "Upload lifetime expired");
+      let client_received_enough c =
+        if !!upload_full_chunks && not !!upload_complete_chunks then
+          c.client_session_uploaded > (block_size ++ 20L ** 1024L)
+        else
+          last_time() > c.client_connect_time + !client_upload_lifetime + 5 * prio
+      in
+      begin
+        if client_received_enough c then
+          if Intmap.length !CommonUploads.pending_slots_map = 0 then lprintf_nl
+            "donkeyClient: not closing upload slot of %s (%s), pending slots empty, sending next block..."
+              (full_client_identifier c) (file_best_name file)
+          else begin
+            DonkeyOneFile.remove_client_slot c;
             raise Not_found
           end;
         
@@ -2072,6 +2053,8 @@
                 up_end_chunk = Int64.zero;
                 up_chunks = [];
 		up_flying_chunks = [];
+                up_current = Int64.zero;
+                up_finish = true;
                 up_waiting = old_up.up_waiting;
               }, old_up.up_waiting
           | _ ->
@@ -2081,18 +2064,30 @@
                 up_end_chunk = Int64.zero;
                 up_chunks = [];
 		up_flying_chunks = [];
+                up_current = ((t.Q.start_pos1 ++ t.Q.end_pos1) // (2L ** block_size));
+                up_finish = false;
                 up_waiting = false;
               }, false
         in
         new_chunk up t.Q.start_pos1 t.Q.end_pos1;
         new_chunk up t.Q.start_pos2 t.Q.end_pos2;
         new_chunk up t.Q.start_pos3 t.Q.end_pos3;
+        (match up.up_chunks with
+          [] ->
+(* it should never happen here, that a client with up.up_finish = false
+   has an empty block queue *)
+            if up.up_finish && !!upload_complete_chunks then
+              begin
+                DonkeyOneFile.remove_client_slot c;
+                raise Not_found
+              end;
+          | chunks ->
         c.client_upload <- Some up;
         set_client_upload (as_client c) (as_file file);
         if not waiting && !CommonUploads.has_upload = 0 then begin
             CommonUploads.ready_for_upload (as_client c);
             up.up_waiting <- true
-          end
+            end)
       end;
       if !verbose_upload then lprintf_nl "QueryBloc treated"
       
--- src/networks/donkey/donkeyFiles.ml	2007-01-07 23:38:52.807340416 +0100
+++ src/networks/donkey/donkeyFiles.ml	2007-01-08 00:52:51.095618040 +0100
@@ -149,6 +149,8 @@
                     if !verbose_upload then
                         lprintf_nl "NO MORE CHUNKS";
 		    up.up_waiting <- false;
+                    if up.up_finish && !!upload_complete_chunks then
+                      DonkeyOneFile.remove_client_slot c;
                 | (begin_pos, end_pos) :: _ ->
                     up.up_pos <- begin_pos;
                     up.up_end_chunk <- end_pos;
--- src/networks/donkey/donkeyOneFile.ml	2007-01-07 23:38:52.794342392 +0100
+++ src/networks/donkey/donkeyOneFile.ml	2007-01-08 00:27:00.070409712 +0100
@@ -100,11 +100,28 @@
                 end
 
 let remove_client_slot c =
+  if c.client_debug || (
+     !verbose &&
+     (c.client_session_uploaded > 0L || c.client_session_downloaded > 0L)) then
+    lprintf_nl "Client[%d] %s disconnected, connected %s%s%s"
+      (client_num c) (full_client_identifier c)
+      (Date.time_to_string (last_time () - c.client_connect_time) "verbose")
+      (if c.client_total_uploaded > 0L then
+        Printf.sprintf ", send %s (%s)%s"
+          (size_of_int64 c.client_session_uploaded)
+          (size_of_int64 c.client_total_uploaded)
+          (match client_upload (as_client c) with | None -> ""
+           | Some f -> " of " ^ (CommonFile.file_best_name f)) else "")
+      (if c.client_total_downloaded > 0L then
+        Printf.sprintf ", rec %s (%s)"
+          (size_of_int64 c.client_session_downloaded)
+          (size_of_int64 c.client_total_downloaded) else "");
   set_client_has_a_slot (as_client c) NoSlot;
   client_send c (
     let module M = DonkeyProtoClient in
-    let module Q = M.CloseSlot in
-    M.CloseSlotReq Q.t);
+    let module Q = M.OutOfParts in
+    M.OutOfPartsReq Q.t);
+  c.client_session_uploaded <- 0L;
   c.client_upload <- None
 
 let unshare_file file =
--- src/networks/donkey/donkeyOptions.ml	2007-01-07 23:38:52.795342240 +0100
+++ src/networks/donkey/donkeyOptions.ml	2007-01-08 00:50:21.160411656 +0100
@@ -174,6 +174,16 @@
   "How long a downloading client can stay in my upload queue (in minutes >5)"
     int_option 90
 
+let upload_full_chunks = define_expert_option donkey_section ["upload_full_chunks"]
+  "If true, each client is allowed to receive one chunk, this setting overrides upload_lifetime"
+    bool_option false
+
+let upload_complete_chunks = define_expert_option donkey_section ["upload_complete_chunks"]
+  "If true, each client is allowed to complete only one chunk, independent, if it is empty or
+   partial. this setting overrides upload_full_chunks and dynamic_upload_lifetime,
+   but is, as a failsafe, limited by upload_lifetime (should be set reasonable high)"
+    bool_option false
+
 let dynamic_upload_lifetime = define_expert_option donkey_section ["dynamic_upload_lifetime"]
   "Each client upload lifetime depends on download-upload ratio"
     bool_option false
--- src/networks/donkey/donkeyProtoClient.ml	2007-01-07 23:38:52.797341936 +0100
+++ src/networks/donkey/donkeyProtoClient.ml	2007-01-08 00:32:08.608504792 +0100
@@ -586,7 +586,7 @@
 
 module AvailableSlot = NoArg(struct let m = "AvailableSlot" end)
 module ReleaseSlot = NoArg(struct let m = "ReleaseSlot" end)
-module CloseSlot = NoArg(struct let m = "CloseSlot" end)
+module OutOfParts = NoArg(struct let m = "OutOfParts" end)
 module ViewFiles = NoArg(struct let m = "VIEW FILES" end)
 module ViewDirs = NoArg(struct let m = "VIEW DIRS" end)
 
@@ -1137,7 +1137,7 @@
 | JoinQueueReq of JoinQueue.t (* sent before queryBloc *)
 | AvailableSlotReq of AvailableSlot.t
 | ReleaseSlotReq of ReleaseSlot.t
-| CloseSlotReq of CloseSlot.t
+| OutOfPartsReq of OutOfParts.t
 | QueryChunksReq of QueryChunks.t
 | QueryChunksReplyReq of QueryChunksReply.t
 | QueryChunkMd4Req of QueryChunkMd4.t
@@ -1184,7 +1184,7 @@
     | JoinQueueReq t -> JoinQueue.print t
     | AvailableSlotReq t -> AvailableSlot.print t
     | ReleaseSlotReq t -> ReleaseSlot.print t
-    | CloseSlotReq t -> CloseSlot.print t
+    | OutOfPartsReq t -> OutOfParts.print t
     | QueryChunksReq t -> QueryChunks.print t
     | QueryChunksReplyReq t -> QueryChunksReply.print t
     | QueryChunkMd4Req t -> QueryChunkMd4.print t
@@ -1417,8 +1417,8 @@
           | 85 -> AvailableSlotReq (AvailableSlot.parse len s)
 (* ReleaseSlot: the upload is finished *)
           | 86 -> ReleaseSlotReq (ReleaseSlot.parse len s)
-(* CloseSlot: the upload slot is not available *)
-          | 87 -> CloseSlotReq (CloseSlot.parse len s)
+(* OutOfParts: the upload slot is not available *)
+          | 87 -> OutOfPartsReq (OutOfParts.parse len s)
           | 88 -> QueryFileReq (QueryFile.parse emule_version len s)
           | 89 -> QueryFileReplyReq (QueryFileReply.parse len s)
           | 92 -> QueueRankReq (QueueRank.parse len s)
@@ -1540,9 +1540,9 @@
     | ReleaseSlotReq t ->
         buf_int8 buf 86;
         ReleaseSlot.write buf t
-    | CloseSlotReq t ->
+    | OutOfPartsReq t ->
         buf_int8 buf 87;
-        CloseSlot.write buf t
+        OutOfParts.write buf t
     | ViewFilesReq t ->
         buf_int8 buf 74;
         ViewFiles.write buf t
--- src/networks/donkey/donkeyTypes.ml	2007-01-07 23:38:52.808340264 +0100
+++ src/networks/donkey/donkeyTypes.ml	2007-01-08 00:50:54.311371944 +0100
@@ -620,6 +620,8 @@
     mutable up_chunks : (int64 * int64) list;
     (* zones sent but not yet received by other peer, oldest first *)
     mutable up_flying_chunks : (int64 * int64) list; 
+    mutable up_current : int64;
+    mutable up_finish : bool;
     mutable up_waiting : bool;
   }
 
