Index: src/networks/donkey/donkeyClient.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/networks/donkey/donkeyClient.ml,v
retrieving revision 1.114
diff -u -w -r1.114 donkeyClient.ml
--- src/networks/donkey/donkeyClient.ml	3 Dec 2006 20:49:42 -0000	1.114
+++ src/networks/donkey/donkeyClient.ml	22 Dec 2006 03:30:01 -0000
@@ -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,17 +415,45 @@
     end
         
   
-let new_chunk up begin_pos end_pos =
-  if begin_pos <> end_pos then
-    let pair = (begin_pos, end_pos) in
+let new_chunks up chunks =
+  if (not up.up_finish) || (not !!upload_complete_chunks) then
+  List.iter (fun ((begin_pos, end_pos) as chunk) ->
+    begin
+    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
+    if (not (List.mem chunk up.up_chunks_served)) ||
+      ((not (List.mem (begin_pos -- zone_size, begin_pos) chunks)) && (not (List.mem (end_pos, end_pos ++ zone_size) chunks))) then
     (match up.up_chunks with
         [] ->
           up.up_pos <- begin_pos;
           up.up_end_chunk <- end_pos;
-          up.up_chunks <- [pair];
+          up.up_chunks <- [chunk];
       | chunks ->
-          if not (List.mem pair chunks) then
-            up.up_chunks <- chunks @ [pair])
+          if not (List.mem chunk chunks) then
+            begin
+              List.iter (fun (b_e, e_e) ->
+                if !verbose && (((begin_pos >= b_e) && (begin_pos < e_e)) || ((end_pos > b_e) && (end_pos <= e_e))) then
+                  lprintf_nl "REREQUEST for file %s block: (%Ld,%Ld) matching served block: (%Ld,%Ld)"
+                    (file_best_name up.up_file) begin_pos end_pos b_e e_e;
+              ) up.up_chunks_served;
+              (match
+                try 
+                  List.find (fun (b_e, e_e) -> ((begin_pos >= b_e) && (begin_pos < e_e)) || ((end_pos > b_e) && (end_pos <= e_e))) chunks
+                with | Not_found -> (Int64.zero,Int64.zero)
+              with
+                (begin_exist, end_exist) ->
+                if begin_exist <> end_exist then
+                  lprintf_nl "blockreq exists, requested block: (%Ld,%Ld) existing block: (%Ld,%Ld)"
+                    begin_pos end_pos begin_exist end_exist);
+              up.up_chunks <- chunks @ [chunk];
+            end;)
+    end
+  ) chunks
   
 let identify_client_brand c =
   if c.client_brand = Brand_unknown then
@@ -1417,7 +1390,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
@@ -1428,6 +1401,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
@@ -1435,7 +1409,7 @@
           [] -> ()
         | _ -> 
             if !verbose_download then
-                lprintf_nl "CloseSlotReq"; 
+                lprintf_nl "OutOfPartsReq"; 
             DonkeyOneFile.request_slot c;
             set_rtimeout sock !!queued_timeout;
       end
@@ -2024,16 +1998,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
@@ -2041,13 +2015,15 @@
           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 ? *)
+      let client_received_enough c =
+          last_time() > c.client_connect_time + !client_upload_lifetime + 5 * prio
+      in
             
-            disconnect_client c (Closed_for_error "Upload lifetime expired");
+      begin
+        if client_received_enough c then
+          begin
+            DonkeyOneFile.remove_client_slot c;
             raise Not_found
           end;
         
@@ -2062,6 +2038,9 @@
                 up_pos = Int64.zero;
                 up_end_chunk = Int64.zero;
                 up_chunks = [];
+                up_chunks_served = [];
+                up_current = Int64.zero;
+                up_finish = true;
                 up_waiting = old_up.up_waiting;
               }, old_up.up_waiting
           | _ ->
@@ -2070,18 +2048,31 @@
                 up_pos = Int64.zero;
                 up_end_chunk = Int64.zero;
                 up_chunks = [];
+                up_chunks_served = [];
+                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;
+        new_chunks up [(t.Q.start_pos1, t.Q.end_pos1);
+		       (t.Q.start_pos2, t.Q.end_pos2);
+		       (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"
       
Index: src/networks/donkey/donkeyFiles.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/networks/donkey/donkeyFiles.ml,v
retrieving revision 1.22
diff -u -w -r1.22 donkeyFiles.ml
--- src/networks/donkey/donkeyFiles.ml	21 Nov 2006 22:34:33 -0000	1.22
+++ src/networks/donkey/donkeyFiles.ml	22 Dec 2006 03:30:01 -0000
@@ -241,10 +241,12 @@
                 up.up_chunks <- chunks;
+                up.up_chunks_served <- up.up_chunks_served @ [(begin_offset,end_offset)];
                 let per_client = per_client - max_len in
                 match chunks with
                   [] -> 
                     if !verbose_upload then
                         lprintf_nl "NO CHUNKS";
-                    c.client_upload <- None;
+                    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;
Index: src/networks/donkey/donkeyOneFile.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/networks/donkey/donkeyOneFile.ml,v
retrieving revision 1.46
diff -u -w -r1.46 donkeyOneFile.ml
--- src/networks/donkey/donkeyOneFile.ml	21 Nov 2006 22:34:34 -0000	1.46
+++ src/networks/donkey/donkeyOneFile.ml	22 Dec 2006 03:30:02 -0000
@@ -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 =
Index: src/networks/donkey/donkeyOptions.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/networks/donkey/donkeyOptions.ml,v
retrieving revision 1.57
diff -u -w -r1.57 donkeyOptions.ml
--- src/networks/donkey/donkeyOptions.ml	26 Nov 2006 16:36:29 -0000	1.57
+++ src/networks/donkey/donkeyOptions.ml	22 Dec 2006 03:30:02 -0000
@@ -174,6 +174,12 @@
   "How long a downloading client can stay in my upload queue (in minutes >5)"
     int_option 90
 
+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 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
Index: src/networks/donkey/donkeyProtoClient.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/networks/donkey/donkeyProtoClient.ml,v
retrieving revision 1.42
diff -u -w -r1.42 donkeyProtoClient.ml
--- src/networks/donkey/donkeyProtoClient.ml	3 Dec 2006 20:49:42 -0000	1.42
+++ src/networks/donkey/donkeyProtoClient.ml	22 Dec 2006 03:30:02 -0000
@@ -585,7 +585,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 = "CloseSlot" end)
 module ViewFiles = NoArg(struct let m = "VIEW FILES" end)
 module ViewDirs = NoArg(struct let m = "VIEW DIRS" end)
 
@@ -1107,7 +1107,7 @@
 | JoinQueueReq of JoinQueue.t (* sent before queryBloc *)
 | AvailableSlotReq of AvailableSlot.t
 | ReleaseSlotReq of ReleaseSlot.t
-| CloseSlotReq of CloseSlot.t
+| OutOfPartsReq of CloseSlot.t
 | QueryChunksReq of QueryChunks.t
 | QueryChunksReplyReq of QueryChunksReply.t
 | QueryChunkMd4Req of QueryChunkMd4.t
@@ -1154,7 +1154,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
@@ -1388,8 +1388,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)
@@ -1509,9 +1509,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
Index: src/networks/donkey/donkeyTypes.ml
===================================================================
RCS file: /sources/mldonkey/mldonkey/src/networks/donkey/donkeyTypes.ml,v
retrieving revision 1.54
diff -u -w -r1.54 donkeyTypes.ml
--- src/networks/donkey/donkeyTypes.ml	2 Dec 2006 12:35:46 -0000	1.54
+++ src/networks/donkey/donkeyTypes.ml	22 Dec 2006 03:30:02 -0000
@@ -616,6 +616,9 @@
     mutable up_pos : int64;
     mutable up_end_chunk : int64;
     mutable up_chunks : (int64 * int64) list;
+    mutable up_chunks_served : (int64 * int64) list;
+    mutable up_current : int64;
+    mutable up_finish : bool;
     mutable up_waiting : bool;
   }
 
