EnableExplicit Procedure.s Tracker_GetBencoding_String(*TorrentMem, *M_Pos, MaxSize, encoding, *ErrFlag) Protected MemPos, Bytes, i Protected Err.b, Char.a, String.s String="" Err = #False MemPos = PeekI(*M_Pos) For i=MemPos To MemPos+18 Char = PeekA(*TorrentMem+i) If Char=':' i+1 Break ElseIf Char<'0' Or Char>'9' Err = #True Break EndIf Next i If Err = #False And Char=':' And i>MemPos+1 And i<=MemPos+18 Bytes = Val(PeekS(*TorrentMem+MemPos, i-MemPos, #PB_Ascii)) If Bytes>=0 And Bytes <= MaxSize-i MemPos + (i-MemPos) If Bytes>0 String = PeekS(*TorrentMem+MemPos, Bytes, encoding) Else String = "" EndIf MemPos + Bytes PokeI(*M_Pos, MemPos) Else Err = #True EndIf Else Err = #True EndIf If Err = #True PokeB(*ErrFlag, 1) EndIf ProcedureReturn String EndProcedure Procedure.q Tracker_GetBencoding_Int(*TorrentMem, *M_Pos, MaxSize, *ErrFlag) Protected MemPos, Int.q, i Protected Err.b, Char.a Int = 0 Err = #False MemPos = PeekI(*M_Pos) Char = PeekA(*TorrentMem+MemPos) If Char='i' Or Char='I' MemPos+1 For i=MemPos To MemPos+18 Char = PeekA(*TorrentMem+i) If Char='e' Or Char='E' i+1 Break ElseIf (Char<'0' Or Char>'9') And Char<>'-' Err = #True Break EndIf Next i If Err = #False And i-MemPos-1 > 0 And (Char='e' Or Char='E') And i<=MemPos+18 Int = Val(PeekS(*TorrentMem+MemPos, i-MemPos-1, #PB_Ascii)) MemPos = i PokeI(*M_Pos, MemPos) Else Err = #True EndIf EndIf If Err = #True PokeB(*ErrFlag, 1) EndIf ProcedureReturn Int EndProcedure Procedure.b Tracker_Bencode_Decoder(Comand.s, *Parameter, *Struct.Tracker_Bencode_Info, *Temp.Byte) Protected Result.b, L_String.s Result = #True If Comand<>"" L_String = LCase(Comand) Select L_String Case "complete" *Struct\Complete = PeekL(*Parameter) Case "incomplete" *Struct\Incomplete = PeekL(*Parameter) Case "downloaded" *Struct\Downloaded = PeekL(*Parameter) Case "interval" *Struct\Interval = PeekL(*Parameter) Case "min interval" *Struct\Min_interval = PeekL(*Parameter) Case "tracker id" *Struct\Tracker_ID = PeekS(*Parameter) Case "failure reason" *Struct\Failure_Reason = PeekS(*Parameter) Case "warning message" *Struct\Warning_Message = PeekS(*Parameter) Case "peer id", "ip", "port" If *Temp\b = 0 *Temp\b = 1 If AddElement(*Struct\Peersld())=0 Result = #False EndIf EndIf If Result = #True Select L_String Case "peer id" *Struct\Peersld()\Peer_id = PeekS(*Parameter) Case "ip" *Struct\Peersld()\IP = PeekS(*Parameter) Case "port" *Struct\Peersld()\Port = PeekU(*Parameter) EndSelect EndIf EndSelect EndIf ProcedureReturn Result EndProcedure Procedure.a Tracker_Bencode_Parser_Compact(*Struct.Tracker_Bencode_Info, *Mem, *PosMem, MaxSize) ; Расшифровка данных при компактном ответе трекера. Protected MemPos, i, Result.a, Char.a Protected Bytes, Pos, Port.u Result = #True MemPos = PeekI(*PosMem) For i=MemPos To MemPos+18 If i<=MaxSize Char = PeekA(*Mem+i) If Char=':' i+1 Break ElseIf Char<'0' Or Char>'9' Result = #False Break EndIf Else Result = #False Break EndIf Next i If Result = #True And i>MemPos+1 And Char=':' And i<=MemPos+18 Bytes = Val(PeekS(*Mem+MemPos, i-MemPos, #PB_Ascii)) If Bytes>0 And Bytes < MaxSize-i If Bytes % 6 = 0 MemPos + (i-MemPos) Pos = MemPos For i=1 To Bytes Step 6 If AddElement(*Struct\Peersld()) *Struct\Peersld()\Peer_id="" *Struct\Peersld()\IP=IPString(PeekL(*Mem+Pos)) : Pos+4 Port = ReverseWord(PeekU(*Mem+Pos)) : Pos+2 *Struct\Peersld()\Port = Port EndIf Next i PokeI(*PosMem, Pos) EndIf Else Result = #False EndIf Else Result = #False EndIf ProcedureReturn Result EndProcedure Procedure Tracker_Bencode_ParserCore(deep, Command.a, ComString.s, *BencodeMem, MaxSizeMem, *Struct.Tracker_Bencode_Info, *PosMem, *ErrState) ; Рекурсионный парсер ответа от трекера. Protected Char.a, State_D.b, Temp_f.byte, MemPos Protected qVar.q, String.s, SubErr.b If deep>=20 Or PeekB(*ErrState)<>0 ProcedureReturn EndIf State_D=0 MemPos = PeekI(*PosMem) Temp_f\b = 0 SubErr = 0 Repeat If deep>=20 Or MemPos>=MaxSizeMem Break EndIf Char = PeekA(*BencodeMem + MemPos) Select Char Case 'd', 'D' ; Найдена директива. MemPos + 1 Tracker_Bencode_ParserCore(deep+1, 'd', ComString, *BencodeMem, MaxSizeMem, *Struct, @MemPos, *ErrState) State_D = 0 : Temp_f\b = 0 Case 'l', 'L' ; Найден список. MemPos + 1 Tracker_Bencode_ParserCore(deep+1, 'l', ComString, *BencodeMem, MaxSizeMem, *Struct, @MemPos, *ErrState) State_D = 0 : Temp_f\b = 0 Case 'i', 'I' ; Найдено число (в символьном виде). SubErr = 0 qVar = Tracker_GetBencoding_Int(*BencodeMem, @MemPos, MaxSizeMem, @SubErr) If SubErr = 0 If State_D <> 0 State_D = 0 If Tracker_Bencode_Decoder(ComString, @qVar, *Struct, @Temp_f) = #False PokeB(*ErrState, 1) EndIf EndIf Else PokeB(*ErrState, 1) EndIf Case '0' To '9' ; Найдена строка. If State_D <> 0 And LCase(ComString)="peers" ; Компактный ответ трекера. State_D = 0 ComString = "" If Tracker_Bencode_Parser_Compact(*Struct, *BencodeMem, @MemPos, MaxSizeMem) = #False PokeB(*ErrState, 1) EndIf Else ; Обычный ответ трекера (не компактный). SubErr = 0 String=Tracker_GetBencoding_String(*BencodeMem, @MemPos, MaxSizeMem, #PB_Ascii, @SubErr) If SubErr = 0 If State_D = 0 And String<>"" State_D = 1 ComString = String Else If Tracker_Bencode_Decoder(ComString, @String, *Struct, @Temp_f) = #False PokeB(*ErrState, 1) EndIf State_D = 0 ComString = "" EndIf Else PokeB(*ErrState, 1) EndIf EndIf Case 'e', 'E' ; Найдена завершающая команда. PokeI(*PosMem, MemPos+1) ProcedureReturn Default MemPos + 1 If deep>0 ;Or MemPos0 PokeI(*PosMem, MemPos) ProcedureReturn EndIf Until deep>=20 Or MemPos>=MaxSizeMem If deep>=20 PokeI(*PosMem, MemPos) ElseIf MemPos>MaxSizeMem And deep>0 PokeI(*PosMem, MemPos) EndIf EndProcedure Procedure.b Tracker_Bencode_GetParser(*MemInfo, LenMem, *Struct.Tracker_Bencode_Info) ; Вызов рекурсионного Bencode парсера ответа от трекера. ;Protected Protected PosMem, ErrState.b PosMem = 0 : ErrState = 0 Tracker_Bencode_ParserCore(0, 0, "", *MemInfo, LenMem, *Struct, @PosMem, @ErrState) ProcedureReturn ErrState EndProcedure Procedure.b Tracker_SetTrackerSite(Connect, *Info.Tracker_SetTracker, TrackerPort.s) ; Запрос трекеру. Protected Result.b, Send.s, TempL.l, TempS.s Protected *Mem, Size.l, Command.s Result = #False If Connect And *Info TempS=*Info\Tracker If TempS<>"" TempL=FindString(TempS, "://", 1) If TempL>0 TempS = Mid(TempS, TempL+3) EndIf TempL=FindString(TempS, "/", 1) If TempL>0 TempS = Mid(TempS, TempL) Send="GET "+TempS If FindString(TempS,"?",1)>0 Send+"&" Else Send+"?" EndIf Else Send = "GET /announce?" EndIf Select *Info\event Case #Tracker_Started Command = "started" Case #Tracker_Stopped Command = "stopped" Case #Tracker_Completed Command = "completed" Default Command = "" EndSelect Send+"info_hash="+URLEncode_Binary(@*Info\info_hash, SizeOf(*Info\info_hash)) Send+"&peer_id="+URLEncode_String(G_ProgramMiscInfo\Network\peer_id) Send+"&port="+Str(G_ProgramSetting\Lan\Port) Send+"&uploaded="+Str(*Info\uploaded) Send+"&downloaded="+Str(*Info\downloaded) Send+"&left="+Str(*Info\left) If *Info\Compact = #False Or *Info\Compact = #True Send+"&compact="+Str(*Info\Compact) EndIf If *Info\Key<>"" Send+"&key="+*Info\Key EndIf If Command<>"" Send+"&event="+Command EndIf If *Info\numwant>0 Send+"&numwant="+Str(*Info\numwant) EndIf If *Info\trackerid<>"" Send+"&trackerid="+*Info\trackerid EndIf If *Info\no_peer_id = #False Or *Info\no_peer_id = #True Send+"&no_peer_id="+Str(*Info\no_peer_id) EndIf Send+" HTTP/1.1"+#CRLF$ Send+"Host: "+GetURLPart(*Info\Tracker, #PB_URL_Site)+TrackerPort+#CRLF$ Send+"User-Agent: "+#ProgName+#CRLF$ Send+"Accept-Encoding: gzip"+#CRLF$ Send+"Connection: close"+#CRLF$+#CRLF$ Size = StringByteLength(Send, #PB_Ascii) If Size>0 *Mem=AllocateMemory(Size+4) If *Mem PokeS(*Mem, Send, Size, #PB_Ascii) If SendNetworkData(Connect, *Mem, Size) = Size Result = #True EndIf FreeMemory(*Mem) EndIf EndIf EndIf EndIf ProcedureReturn Result EndProcedure Procedure Tracker_GetInfo_Parsing(*mem_, DataPos, Content_Length, gzip, *Err.String, *Point.Pointer) Protected Result, Temp, gzip_out_size, *Mem_gzip, *mem, i, Char.a *mem = PeekI(*mem_) Result = 0 Temp=$088B1F : gzip_out_size = 0 If gzip = #True Or CompareMemory(*mem+DataPos, @Temp, 3) ; Данные упакованы по алгоритму gzip. Temp = Content_Length*10+10000 *Mem_gzip = AllocateMemory(Temp) If *Mem_gzip gzip_out_size = G_ZIP_UnPack(*mem+DataPos, Content_Length+1, *Mem_gzip, @Temp) If gzip_out_size > 0 And Temp<=Content_Length*10+10000 FreeMemory(*mem) For i=gzip_out_size To 0 Step -1 Char=PeekA(*Mem_gzip+i) If Char='e' Or Char='E' gzip_out_size = i+1 Break EndIf Next i *mem = *Mem_gzip Content_Length = gzip_out_size DataPos=0 Else FreeMemory(*Mem_gzip) gzip_out_size=0 EndIf EndIf EndIf *Point\P = AllocateMemory(Content_Length+4) If *Point\P CopyMemory(*mem+DataPos, *Point\P, Content_Length) Result = Content_Length Else *Err\s = "Ошибка выделения памяти." EndIf FreeMemory(*mem) PokeI(*mem_, 0) ProcedureReturn Result EndProcedure Procedure Tracker_DelChunked(*PointMem, DataPos, LenMem, Separator.s) Protected Result, SourceMemPos, LenData, *Mem Protected MemPos, String.s, Err.a, Pos Protected Temp, *SourceMem Pos = 0 : Result = 0 : SourceMemPos = DataPos : MemPos = 0 Err = #False If *PointMem And LenMem>0 And Separator<>"" *SourceMem = PeekI(*PointMem) If *SourceMem *Mem = AllocateMemory(LenMem) If *Mem Repeat String = PeekS(*SourceMem+SourceMemPos, -1, #PB_Ascii) Pos = FindString(String, Separator, 1) If Pos>0 Pos-1 SourceMemPos+Pos SourceMemPos + StringByteLength(Separator, #PB_Ascii) String = Left(String, Pos) If String<>"" And TestNumber_Hex(String)=#True Temp = Val("$"+String) If Temp>0 CopyMemory(*SourceMem+SourceMemPos, *Mem+MemPos, Temp) SourceMemPos+Temp : MemPos+Temp Repeat String = PeekS(*SourceMem+SourceMemPos, -1, #PB_Ascii) If FindString(String, Separator, 1)=1 SourceMemPos + StringByteLength(Separator, #PB_Ascii) Else Break EndIf Until SourceMemPos>=LenMem Else If Temp=0 ; Найден конец данных - нулевой пакет. Repeat String = PeekS(*SourceMem+SourceMemPos, -1, #PB_Ascii) If FindString(String, Separator, 1)=1 SourceMemPos + StringByteLength(Separator, #PB_Ascii) Else Break EndIf Until SourceMemPos>=LenMem Break Else Err = #True Break ; Ошибка. EndIf EndIf Else Err = #True Break ; Ошибка. EndIf Else Err = #True Break ; Ошибка. EndIf Until SourceMemPos>=LenMem If SourceMemPos>=LenMem And MemPos>0 And Err = #False FreeMemory(*SourceMem) PokeI(*PointMem, *Mem) Result = MemPos Else FreeMemory(*Mem) EndIf EndIf EndIf EndIf ProcedureReturn Result EndProcedure Procedure Tracker_GetInfo(Connect, *Point.Pointer, *Err.String, *Location.String) ; Получение ответа от трекера. Protected *Mem, MemPos.l, Count.u, Err.b Protected Len, Result, Header.b, String.s Protected Temp, Pos, Pos_1, Separator.s Protected L_String.s, TempS.s Protected Content_Length.l, DataPos.l, gzip.a, *Mem_gzip Protected gzip_out_size, ChunkedState.a If Connect=0 Or *Point=0 Or *Err=0 ProcedureReturn 0 EndIf Result = 0 Pos = 0 Count=300 Header = 0 Err = #False Separator="" Content_Length=0 DataPos = 0 gzip = #False ChunkedState=#False *Point\P = 0 *Location\s = "" *mem=AllocateMemory(65536*2+1024) If *mem Repeat If NetworkClientEvent(Connect)=#PB_NetworkEvent_Data Len=ReceiveNetworkData(Connect, *mem+MemPos, 65536) MemPos+Len Count = 10 If MemPos>65536 Err = #True *Err\s = "Несогласование данных (>65536)." Break EndIf If DataPos=0 String = PeekS(*mem, Len, #PB_Ascii) Separator = "" Pos = FindString(String, Chr(10), 1) Pos_1 = FindString(String, Chr(13), 1) If Pos>0 Or Pos_1>0 If Pos>0 And Pos_1>0 If Pos+1=Pos_1 Separator = Chr(10)+Chr(13) ElseIf Pos-1=Pos_1 Separator = Chr(13)+Chr(10) EndIf Else If Pos>0 And Pos_1=0 Separator = Chr(10) ElseIf Pos=0 And Pos_1>0 Separator = Chr(13) EndIf EndIf L_String = LCase(String) If Separator <>"" Pos = FindString(L_String, "http/",1) If Pos>0 Pos_1 = FindString(L_String, " ", Pos) If Pos_1>0 If DataPos=0 Pos=FindString(String, Separator+Separator, Pos_1) If Pos>0 ; Нашли начало данных. DataPos = Pos+Len(Separator+Separator)-1 EndIf EndIf If DataPos>0 Pos=FindString(L_String, Separator, Pos_1) If Pos>0 And DataPos>Pos TempS = Trim(Mid(L_String, Pos_1+1, Pos-Pos_1-1)) Pos_1 = FindString(TempS, " ", 2) If Pos_1 TempS = Mid(TempS, 1, Pos_1-1) EndIf If TempS="200";ok If gzip = #False Pos = FindString(L_String, "content-encoding:",1) If Pos>0 And DataPos>Pos Pos_1 = FindString(L_String, Separator, Pos) If Pos_1 TempS = Trim(Mid(L_String, Pos, Pos_1-Pos), " ") If FindString(TempS, "gzip", 1)>0 Or FindString(TempS, "deflate", 1)>0 gzip = #True EndIf EndIf EndIf EndIf If ChunkedState=#False Pos = FindString(L_String, "transfer-encoding:",1) If Pos>0 And DataPos>Pos Pos_1 = FindString(L_String, Separator, Pos) If Pos_1 TempS = Trim(Mid(L_String, Pos, Pos_1-Pos), " ") If FindString(TempS, "chunked", 1)>0 ChunkedState = #True EndIf EndIf EndIf EndIf Pos = FindString(L_String, "content-length:",1) If Pos>0 And DataPos>Pos Pos_1 = FindString(L_String, Separator, Pos) If Pos_1>0 Pos+Len("content-length:") TempS = Trim(Mid(L_String, Pos, Pos_1-Pos), " ") If TempS<>"" And TestNumber(TempS)=#True Temp = Val(TempS) If Temp>0 Content_Length = Temp EndIf EndIf EndIf EndIf ElseIf TempS="301" Or TempS="302" Or TempS="303" Or TempS="304" Or TempS="307" ; Ошибка Moved Permanently (Перемещено окончательно). Pos = FindString(L_String, "location:",1) If Pos>0 And DataPos>Pos Pos_1 = FindString(L_String, Separator, Pos) If Pos_1>0 Pos+Len("location:") TempS = Trim(Mid(L_String, Pos, Pos_1-Pos), " ") If TempS<>"" *Location\s = TempS Err = #True Result = 0 Break EndIf EndIf EndIf Else Err = #True Pos_1 = FindString(String, " ", 2) *Err\s = "Ошибка "+Chr(34)+Mid(String, Pos_1+1, Pos-Pos_1-1)+Chr(34)+"." Break EndIf EndIf EndIf EndIf EndIf EndIf EndIf EndIf If DataPos>0 ; Заголовок отдеклен от данных и в DataPos позиция начала данных. If MemPos<=DataPos+Content_Length ; Все данные получены. Result = Tracker_GetInfo_Parsing(@*mem, DataPos, Content_Length, gzip, *Err, *Point) Break EndIf EndIf Else Pos_1=0 DisableDebugger ; Кривой велосипед, но вроде работающий. SendNetworkData(Connect, @Pos_1, 0) ; Проверка на закрытие коннекта трекером. Pos = WSAGetLastError_() EnableDebugger If Pos If DataPos<=0 *Mem_gzip = AllocateMemory(1024) If *Mem_gzip FillMemory(*Mem_gzip, 1024, 0) Pos_1=FormatMessage_(#FORMAT_MESSAGE_FROM_SYSTEM, 0, Pos, 0, *Mem_gzip, 1024, 0) If Pos_1>0 *Err\s = PeekS(*Mem_gzip, Pos_1) EndIf FreeMemory(*Mem_gzip) EndIf Else Count=0 EndIf Break EndIf Delay(32) Count-1 If Count<=0 If DataPos>0 ;ShowMemoryViewer(*mem, MemPos) If ChunkedState = #True Temp = Tracker_DelChunked(@*mem, DataPos, MemPos, Separator) If Temp>0 MemPos = Temp DataPos=0 EndIf EndIf Result = Tracker_GetInfo_Parsing(@*mem, DataPos, MemPos-DataPos, gzip, *Err, *Point) ;ShowMemoryViewer(*Point\P, Result) ElseIf Header = #False Err = #True *Err\s = "Трекер не ответил на GET запрос." Else Err = #True *Err\s = "Сброс по таймауту." EndIf Break EndIf EndIf Until Err = #True If *mem FreeMemory(*mem) *mem=0 EndIf EndIf ProcedureReturn Result EndProcedure Procedure Tracker_AddPeerList(NumTracker.l, *Peer.Tracker_Bencode_Info) ; Добавление пиров в список. Protected x.b, NewPeer.Tracker_Bencode_Info_PeerList ForEach *Peer\Peersld() NewPeer\Peer_id = *Peer\Peersld()\Peer_id NewPeer\IP = *Peer\Peersld()\IP NewPeer\Port = *Peer\Peersld()\Port If NewPeer\Peer_id <> G_ProgramMiscInfo\Network\peer_id x=0 ForEach G_TorrentList\TorrentList()\Network\PeerList() If (G_TorrentList\TorrentList()\Network\PeerList()\Peer_id=NewPeer\Peer_id Or NewPeer\Peer_id="") And G_TorrentList\TorrentList()\Network\PeerList()\IP$=NewPeer\IP And G_TorrentList\TorrentList()\Network\PeerList()\Port=NewPeer\Port x=1 ; В этом торренте, такой пир уже есть. Break EndIf Next If x=0 ; Информации о пире нет - нужно добавить. LastElement(G_TorrentList\TorrentList()\Network\PeerList()) If AddElement(G_TorrentList\TorrentList()\Network\PeerList()) G_TorrentList\TorrentList()\Network\PeerList()\Peer_id = NewPeer\Peer_id G_TorrentList\TorrentList()\Network\PeerList()\IP$ = NewPeer\IP G_TorrentList\TorrentList()\Network\PeerList()\IP = ip2int(NewPeer\IP) G_TorrentList\TorrentList()\Network\PeerList()\Port = NewPeer\Port G_TorrentList\TorrentList()\Network\PeerList()\NumTracker = NumTracker G_TorrentList\TorrentList()\Network\PeerList()\Out_Table\Domains = "" G_TorrentList\TorrentList()\Network\PeerList()\Out_Table\Flag = -1 G_TorrentList\TorrentList()\Network\PeerList()\Out_Table\Local = "" If NewPeer\Peer_id<>"" G_TorrentList\TorrentList()\Network\PeerList()\Out_Table\Client = ClientName(NewPeer\Peer_id) EndIf G_TorrentList\TorrentList()\Network\PeerList()\Active = #False ;True EndIf EndIf EndIf Next EndProcedure Procedure Tracker_FreePeerList() ; Удаление инфы о пирах. Торрент должет быть выбран в списке и доступ к нему должен быть заблокироан мьюльтексом. ClearList(G_TorrentList\TorrentList()\Network\PeerList()) EndProcedure Procedure Tracker_Redirection(Address.s, *Point, *ErrString.String, *Location.String) ; Вызывается если при обращении к трекеру произошла ошибка 30x - перенаправление. Protected Result, Site.s, TempS.s, TrackerPort.s Protected Port.u, TempL.l, Send.s, Size Protected *Mem, Connect Result = 0 TrackerPort = "" Site=GetURLPart(Address, #PB_URL_Site) If Site TempS = GetURLPart(Address, #PB_URL_Port) If TempS<>"" Port = Val(TempS) If Port<=0 Port = 80 Else TrackerPort = ":"+TempS EndIf Else Port = 80 EndIf Connect=OpenNetworkConnection(Site, Port) If Connect TempS = Address TempL=FindString(TempS, "://", 1) If TempL>0 TempS = Mid(TempS, TempL+3) EndIf TempL=FindString(TempS, "/", 1) If TempL>0 TempS = Mid(TempS, TempL) Send="GET "+TempS+" HTTP/1.1"+#CRLF$ Send+"Host: "+Site+TrackerPort+#CRLF$ Send+"User-Agent: "+#ProgName+#CRLF$ Send+"Accept-Encoding: gzip"+#CRLF$ Send+"Connection: close"+#CRLF$+#CRLF$ ;Debug Send Size = StringByteLength(Send, #PB_Ascii) If Size>0 *Mem=AllocateMemory(Size+4) If *Mem PokeS(*Mem, Send, Size, #PB_Ascii) If SendNetworkData(Connect, *Mem, Size) = Size Result = Tracker_GetInfo(Connect, *Point, *ErrString, *Location) EndIf FreeMemory(*Mem) EndIf EndIf EndIf CloseNetworkConnection(Connect) EndIf EndIf ProcedureReturn Result EndProcedure Procedure Tracker_RefreshInfo_Tracker(*Info.Tracker_Bencode_Info) ; Вслучае успешного получения данных от трекера, происходит обновление информации, о числе пиров трекера и всего торрента и др. данных. G_TorrentList\TorrentList()\Network_IO\AllSeeds + (*Info\Complete - G_TorrentList\TorrentList()\Network\Tracker()\Complete) G_TorrentList\TorrentList()\Network_IO\AllPeers + (*Info\Incomplete - G_TorrentList\TorrentList()\Network\Tracker()\Incomplete) G_TorrentList\TorrentList()\Network\Tracker()\Complete = *Info\Complete G_TorrentList\TorrentList()\Network\Tracker()\Incomplete = *Info\Incomplete EndProcedure Procedure Tracker_SetTracker(*Info.ProgramStatus_Network_TrackerTaskList) ; Процедура обращения к трекру. Protected INFO_Hash.s, TrackerAddress.s, CountList.l, TrackerPort.s Protected x, Site.s, TempS.s, Port.u Protected Connect, *Point, ErrString.String, ParserError.a Protected Tracker.Tracker_SetTracker, TempL.l Protected Tracker_Info.Tracker_Bencode_Info Protected Command.a, RedirectionCount.a, Location.String;, RefreshTorrent.a Protected TableNotify_Sate.a, Protocol If *Info INFO_Hash = *Info\INFO_Hash TrackerAddress = *Info\Server *Info = 0 *Point=0 x = 0 ErrString\s="" Location\s="" TrackerPort = "" Connect = 0 ParserError = 0 RedirectionCount = 0 TableNotify_Sate = #False ;RefreshTorrent = 0 LockMutex(G_TorrentList\Mutex) ForEach G_TorrentList\TorrentList() If G_TorrentList\TorrentList()\TorrentFile\INFO_Hash = INFO_Hash CopyMemory(@G_TorrentList\TorrentList()\TorrentFile\INFO_HashBin, @Tracker\info_hash, SizeOf(Tracker\info_hash)) ForEach G_TorrentList\TorrentList()\Network\Tracker() If G_TorrentList\TorrentList()\Network\Tracker()\Address = TrackerAddress Tracker\Tracker = G_TorrentList\TorrentList()\Network\Tracker()\Address Tracker\event = G_TorrentList\TorrentList()\Network\Tracker()\Command Tracker\uploaded = G_TorrentList\TorrentList()\Network\Tracker()\Uploaded Tracker\downloaded = G_TorrentList\TorrentList()\Network\Tracker()\Downloaded Tracker\left = G_TorrentList\TorrentList()\TorrentFile\All_Size-G_TorrentList\TorrentList()\Torrent\CurrentFileSize ;G_TorrentList\TorrentList()\Network\Tracker()\Left Tracker\trackerid = G_TorrentList\TorrentList()\Network\Tracker()\TrackerID x = 1 Break EndIf Next Break EndIf Next UnlockMutex(G_TorrentList\Mutex) If x = 1 x = 0 Site=GetURLPart(Tracker\Tracker, #PB_URL_Site) If Site TempS = GetURLPart(Tracker\Tracker, #PB_URL_Port) If TempS<>"" Port = Val(TempS) If Port<=0 Port = 80 Else TrackerPort = ":"+TempS EndIf Else Port = 80 EndIf If LCase(GetURLPart(Tracker\Tracker, #PB_URL_Protocol))="udp" Protocol = #PB_Network_UDP Else Protocol = #PB_Network_TCP EndIf Tracker\numwant = 200 ;5 Tracker\port = G_ProgramSetting\Lan\Port Tracker\Compact = 0 ;1 Tracker\no_peer_id = 0 ;1 Tracker\Key = G_ProgramMiscInfo\Network\Key_Hex Connect=OpenNetworkConnection(Site, Port, Protocol) If Connect If Protocol = #PB_Network_UDP ; UDP трекер. If UDP_Tracker_Request(Connect, @Tracker, @Tracker_Info, @ErrString) = 1 x=0 Else x=1 EndIf Else ; TCP трекер. If Tracker_SetTrackerSite(Connect, @Tracker, TrackerPort) = #True Location\s="" x = Tracker_GetInfo(Connect, @*Point, @ErrString, @Location) If Location\s<>"" ; Переадресация. TempS=ErrString\s RedirectionCount = 0 Repeat ErrString\s="" If *Point FreeMemory(*Point) *Point=0 EndIf TempL=Tracker_Redirection(Location\s, @*Point, @ErrString, @Location) If ErrString\s="" And TempL>0 And Location\s="" And *Point ; ОК, данные получены без ошибок. x=TempL Break ElseIf ErrString\s<>"" x=TempL If *Point FreeMemory(*Point) *Point=0 EndIf Break ElseIf Location\s<>"" Else ErrString\s=TempS Break EndIf RedirectionCount+1 Until RedirectionCount>=10 EndIf ;ShowMemoryViewer(*Point, x) If x>0 And *Point And (Command=#Tracker_Empty Or Command=#Tracker_Started) ParserError = Tracker_Bencode_GetParser(*Point, x, @Tracker_Info) ; Вызов рекурсионного Bencode парсера ответа от трекера. EndIf If *Point FreeMemory(*Point) *Point=0 EndIf Else ErrString\s = "Ошибка GET запроса" EndIf EndIf CloseNetworkConnection(Connect) Else ErrString\s = "Ошибка при соединении с сервером" EndIf Else ErrString\s = "Некорректный адрес трекера" EndIf LockMutex(G_TorrentList\Mutex) CountList = 0 ForEach G_TorrentList\TorrentList() If G_TorrentList\TorrentList()\TorrentFile\INFO_Hash = INFO_Hash ForEach G_TorrentList\TorrentList()\Network\Tracker() If G_TorrentList\TorrentList()\Network\Tracker()\Address = TrackerAddress G_TorrentList\TorrentList()\Network\Tracker()\ErrorString = ErrString\s G_TorrentList\TorrentList()\Network\Tracker()\Warning_Message_Err = 0 If Connect=0 Or(x=0 And Protocol = #PB_Network_UDP) G_TorrentList\TorrentList()\Network\Tracker()\Error=1 If G_TorrentList\TorrentList()\Network\Tracker()\CountNoConnect <= #TrackerStatus_CountNoConnect G_TorrentList\TorrentList()\Network\Tracker()\CountNoConnect + 1 EndIf Select G_TorrentList\TorrentList()\Network\Tracker()\CountNoConnect Case 1 G_TorrentList\TorrentList()\Network\Tracker()\Interval = 60 Case 2 G_TorrentList\TorrentList()\Network\Tracker()\Interval = 2*60 Case 3 G_TorrentList\TorrentList()\Network\Tracker()\Interval = 4*60 Case 4 G_TorrentList\TorrentList()\Network\Tracker()\Interval = 10*60 Default G_TorrentList\TorrentList()\Network\Tracker()\Interval = 20*60 EndSelect Else G_TorrentList\TorrentList()\Network\Tracker()\CountNoConnect = 0 If G_TorrentList\TorrentList()\Network\Tracker()\Command=#Tracker_Empty Or G_TorrentList\TorrentList()\Network\Tracker()\Command=#Tracker_Started If x<=0 G_TorrentList\TorrentList()\Network\Tracker()\Error=1 Else If ParserError=0 G_TorrentList\TorrentList()\Network\Tracker()\Error=0 If Tracker_Info\Tracker_ID<>"" G_TorrentList\TorrentList()\Network\Tracker()\TrackerID = Tracker_Info\Tracker_ID EndIf If Tracker_Info\Warning_Message<>"" G_TorrentList\TorrentList()\Network\Tracker()\Warning_Message_Err = 1 G_TorrentList\TorrentList()\Network\Tracker()\ErrorString = Tracker_Info\Warning_Message G_TorrentList\TorrentList()\Network\Tracker()\Old_Command = #Tracker_Empty G_TorrentList\TorrentList()\Network\Tracker()\Command=#Tracker_Stopped ElseIf Tracker_Info\Failure_Reason G_TorrentList\TorrentList()\Network\Tracker()\Warning_Message_Err = 1 G_TorrentList\TorrentList()\Network\Tracker()\ErrorString = Tracker_Info\Failure_Reason G_TorrentList\TorrentList()\Network\Tracker()\Old_Command = #Tracker_Empty G_TorrentList\TorrentList()\Network\Tracker()\Command=#Tracker_Stopped EndIf If Tracker_Info\Interval>0 If Tracker_Info\Interval<60 : Tracker_Info\Interval=60 : EndIf G_TorrentList\TorrentList()\Network\Tracker()\Interval = Tracker_Info\Interval EndIf If Tracker_Info\Min_interval>0 If Tracker_Info\Min_Interval<60 : Tracker_Info\Min_Interval=60 : EndIf G_TorrentList\TorrentList()\Network\Tracker()\Min_Interval = Tracker_Info\Min_Interval EndIf Tracker_AddPeerList(G_TorrentList\TorrentList()\Network\Tracker()\NumTracker, @Tracker_Info) ; Добавление пиров в список. Tracker_RefreshInfo_Tracker(Tracker_Info) ; Вслучае успешного получения данных от трекера, происходит обновление информации, о числе пиров трекера и всего торрента и др. данных. ;RefreshTorrent = 1 Else G_TorrentList\TorrentList()\Network\Tracker()\ErrorString = "Ошибка при интерпретации ответа" G_TorrentList\TorrentList()\Network\Tracker()\Error=1 EndIf EndIf EndIf If G_TorrentList\TorrentList()\Network\Tracker()\Command=#Tracker_Started Or G_TorrentList\TorrentList()\Network\Tracker()\Command = #Tracker_Stopped If G_TorrentList\TorrentList()\Network\Tracker()\ErrorString = "" G_TorrentList\TorrentList()\Network\Tracker()\Old_Command = G_TorrentList\TorrentList()\Network\Tracker()\Command EndIf EndIf G_TorrentList\TorrentList()\Network\Tracker()\Command = #Tracker_Empty EndIf If G_TorrentList\TorrentList()\Network\Tracker()\CountNoConnect<=0 If G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime<=0 If G_TorrentList\TorrentList()\Network\Tracker()\Interval>=4*60 Or (G_TorrentList\TorrentList()\Network\Tracker()\Interval>=60 And Connect=0) G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime = G_TorrentList\TorrentList()\Network\Tracker()\Interval ElseIf G_TorrentList\TorrentList()\Network\Tracker()\Min_Interval>=4*60 G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime = G_TorrentList\TorrentList()\Network\Tracker()\Min_Interval Else G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime = 20*60 EndIf EndIf Else If G_TorrentList\TorrentList()\Network\Tracker()\Interval>0 G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime = G_TorrentList\TorrentList()\Network\Tracker()\Interval Else G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime = 10*60 EndIf EndIf Break EndIf Next ; Если нет коннекта со всети трекерами торрента, то меяем значок в таблице. x=1 ForEach G_TorrentList\TorrentList()\Network\Tracker() If G_TorrentList\TorrentList()\Network\Tracker()\Error=0 And G_TorrentList\TorrentList()\Network\Tracker()\Warning_Message_Err = 0 x=0 Break EndIf Next Command = G_TorrentList\TorrentList()\Network\Tracker()\Command If Command = #Tracker_Empty Or Command = #Tracker_Started Or Command = #Tracker_Completed If x <> G_TorrentList\TorrentList()\Network\Error_Tracker G_TorrentList\TorrentList()\Network\Error_Tracker = x If G_ProgramMiscInfo\Torrent_All_Pause<>#True And (G_TorrentList\TorrentList()\TorrentStatus=#TorrentStatus_Load Or G_TorrentList\TorrentList()\TorrentStatus=#TorrentStatus_Seed) TableNotify_Sate = #True Command = G_TorrentList\TorrentList()\TorrentStatus EndIf EndIf EndIf Break EndIf CountList + 1 Next UnlockMutex(G_TorrentList\Mutex) If TableNotify_Sate=#True If Test_LockMutex(G_ProgramMiscInfo\TorrentListIcon_Mutex, 400) = #True If x=1 ; Ошибка. If Command = #TorrentStatus_Load SetIcon_TorrentListIcon(#MainWin_ListIcon_Torrent, CountList, #MainWin_TorrentIcon_red_down) Else SetIcon_TorrentListIcon(#MainWin_ListIcon_Torrent, CountList, #MainWin_TorrentIcon_red_up) EndIf Else ; Ошибки нет. If Command = #TorrentStatus_Load SetIcon_TorrentListIcon(#MainWin_ListIcon_Torrent, CountList, #MainWin_TorrentIcon_down) Else SetIcon_TorrentListIcon(#MainWin_ListIcon_Torrent, CountList, #MainWin_TorrentIcon_up) EndIf EndIf UnlockMutex(G_ProgramMiscInfo\TorrentListIcon_Mutex) PostMessage_(GadgetID(#MainWin_ListIcon_Torrent), #LVM_UPDATE, CountList, 0) EndIf EndIf EndIf EndIf EndProcedure Procedure Tracker_Stopped_All_Tracker() ; Процедура вызывается при завершении работы программы и посылвает сигнал оснавновки трекерам. Protected INFO_Hash.s, x.b Protected NewList TaskTrackerList.ProgramStatus_Network_TrackerTaskList() If Test_LockMutex(G_TorrentList\Mutex, 2000)=#True ForEach G_TorrentList\TorrentList() INFO_Hash = G_TorrentList\TorrentList()\TorrentFile\INFO_Hash ForEach G_TorrentList\TorrentList()\Network\Tracker() If G_TorrentList\TorrentList()\Network\Tracker()\Old_Command=#Tracker_Started ; Этому трекеру нужно отправить команду #Tracker_Stopped G_TorrentList\TorrentList()\Network\Tracker()\Command = #Tracker_Stopped If G_TorrentList\TorrentList()\Network\Tracker()\CountNoConnect <= #TrackerStatus_CountNoConnect ; Информируем трекер, только если с ним стабильная связь. If AddElement(TaskTrackerList()) TaskTrackerList()\INFO_Hash = INFO_Hash TaskTrackerList()\Server = G_TorrentList\TorrentList()\Network\Tracker()\Address EndIf EndIf EndIf Next Next UnlockMutex(G_TorrentList\Mutex) EndIf If ListSize(TaskTrackerList())>0 If Test_LockMutex(G_ProgramMiscInfo\Network\TrackerTask_Mutex, 2000) ResetList(G_ProgramMiscInfo\Network\TrackerTask_List()) ; Задание имеет преоритет перед другими, поэтому помещаем его в начало списка. ForEach TaskTrackerList() If AddElement(G_ProgramMiscInfo\Network\TrackerTask_List()) G_ProgramMiscInfo\Network\TrackerTask_List()\INFO_Hash = TaskTrackerList()\INFO_Hash G_ProgramMiscInfo\Network\TrackerTask_List()\Server = TaskTrackerList()\Server G_ProgramMiscInfo\Network\TrackerTask_List()\Status = #Tracker_Stopped G_ProgramMiscInfo\Network\TrackerTask_List()\Active = 0 EndIf Next UnlockMutex(G_ProgramMiscInfo\Network\TrackerTask_Mutex) EndIf EndIf If G_ProgramMiscInfo\ProgEndSate <> 0 ; Прггамма завершает работу. G_ProgramMiscInfo\Network\TrackerTask_EndThread = 1 ; Надо завершить поток. EndIf SignalSemaphore(G_ProgramMiscInfo\Network\TrackerTask_Semaphore) EndProcedure Procedure Tracker_CountTimes(Sec) ; Подсчет времени до обновления информации с трекера и постановка в серверов в очередь обновления. Protected INFO_Hash.s, x.b, Update.b Protected NewList TaskTrackerList.ProgramStatus_Network_TrackerTaskList() Static Plus If Test_LockMutex(G_TorrentList\Mutex, 100) = #True ForEach G_TorrentList\TorrentList() INFO_Hash = G_TorrentList\TorrentList()\TorrentFile\INFO_Hash ForEach G_TorrentList\TorrentList()\Network\Tracker() x = G_TorrentList\TorrentList()\TorrentStatus If x<>#TorrentStatus_Error If G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime>0 G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime - Sec - Plus EndIf If G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime<=0 ; Нужно обновить трекер. If G_ProgramMiscInfo\Torrent_All_Pause<>#True And (x = #TorrentStatus_Load Or x = #TorrentStatus_Seed) ; Торрент не на паузе. ;If G_TorrentList\TorrentList()\Network\Tracker()\CountNoConnect <= #Tracker_CountNoConnect ; Число ошибок коннекта, следующих друг за другом, не превысило допустимый предел. If AddElement(TaskTrackerList()) TaskTrackerList()\INFO_Hash = INFO_Hash TaskTrackerList()\Server = G_TorrentList\TorrentList()\Network\Tracker()\Address EndIf ;EndIf EndIf EndIf EndIf Next Next UnlockMutex(G_TorrentList\Mutex) Plus = 0 Else Plus + Sec EndIf Update = 0 If ListSize(TaskTrackerList())>0 If Test_LockMutex(G_ProgramMiscInfo\Network\TrackerTask_Mutex, 100) = #True ForEach TaskTrackerList() x=0 ForEach G_ProgramMiscInfo\Network\TrackerTask_List() If G_ProgramMiscInfo\Network\TrackerTask_List()\INFO_Hash = TaskTrackerList()\INFO_Hash And G_ProgramMiscInfo\Network\TrackerTask_List()\Server = TaskTrackerList()\Server x=1 ; Такое задание уже есть в списке. Break EndIf Next If x=0 ; Такого трекера нет в списке заданий обновления. LastElement(G_ProgramMiscInfo\Network\TrackerTask_List()) ; Переход на последний элемент списка. If AddElement(G_ProgramMiscInfo\Network\TrackerTask_List()) Update = 1 G_ProgramMiscInfo\Network\TrackerTask_List()\INFO_Hash = TaskTrackerList()\INFO_Hash G_ProgramMiscInfo\Network\TrackerTask_List()\Server = TaskTrackerList()\Server G_ProgramMiscInfo\Network\TrackerTask_List()\Status = #Tracker_Empty G_ProgramMiscInfo\Network\TrackerTask_List()\Active = 0 EndIf EndIf Next UnlockMutex(G_ProgramMiscInfo\Network\TrackerTask_Mutex) EndIf If Update = 1 ; Были добавлены задания, поэтому информирует соответсвующий поток об этом. SignalSemaphore(G_ProgramMiscInfo\Network\TrackerTask_Semaphore) EndIf EndIf EndProcedure Procedure Tracker_StartStop(INFO_Hash.s, Status) ; Информирование торекера что торрент был запущен или остановлен (Только #Tracker_Started или #Tracker_Stopped). Protected NewList TaskTrackerList.ProgramStatus_Network_TrackerTaskList() Protected x.a If Status=#Tracker_Started Or Status=#Tracker_Stopped If Test_LockMutex(G_TorrentList\Mutex, 1000)=#True ForEach G_TorrentList\TorrentList() If INFO_Hash = G_TorrentList\TorrentList()\TorrentFile\INFO_Hash ForEach G_TorrentList\TorrentList()\Network\Tracker() ;If G_TorrentList\TorrentList()\Network\Tracker()\Old_Command<>Status And (G_TorrentList\TorrentList()\Network\Tracker()\Old_Command=#Tracker_Empty And Status<>#Tracker_Started) ; Для того, чтобы подряд не отправлять трекеру одни и теже команды. If G_TorrentList\TorrentList()\Network\Tracker()\Old_Command<>Status If G_TorrentList\TorrentList()\Network\Tracker()\Old_Command=#Tracker_Empty And Status<>#Tracker_Stopped Goto Tracker_StartStop_m1 ElseIf G_TorrentList\TorrentList()\Network\Tracker()\Old_Command<>#Tracker_Empty Tracker_StartStop_m1: G_TorrentList\TorrentList()\Network\Tracker()\Command = Status If Status=#Tracker_Started G_TorrentList\TorrentList()\Network\Tracker()\Downloaded = 0 G_TorrentList\TorrentList()\Network\Tracker()\Uploaded = 0 G_TorrentList\TorrentList()\Network\Tracker()\Complete = 0 G_TorrentList\TorrentList()\Network\Tracker()\Incomplete = 0 G_TorrentList\TorrentList()\Network\Tracker()\Error = 0 G_TorrentList\TorrentList()\Network\Tracker()\Left = G_TorrentList\TorrentList()\Torrent\Torrent_FileSize - G_TorrentList\TorrentList()\Torrent\CurrentFileSize G_TorrentList\TorrentList()\Network\Tracker()\Warning_Message_Err = 0 G_TorrentList\TorrentList()\Network\Tracker()\ErrorString = "" G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime = 2 ElseIf Status=#Tracker_Stopped G_TorrentList\TorrentList()\Network\Tracker()\Error=0 G_TorrentList\TorrentList()\Network\Tracker()\ErrorString="" G_TorrentList\TorrentList()\Network\Tracker()\Warning_Message_Err=0 G_TorrentList\TorrentList()\Network\Tracker()\UpdateTime = 300 G_TorrentList\TorrentList()\Network\Tracker()\Complete = 0 G_TorrentList\TorrentList()\Network\Tracker()\Incomplete = 0 G_TorrentList\TorrentList()\Network\Tracker()\CountNoConnect = 0 G_TorrentList\TorrentList()\Network_IO\AllSeeds = 0 G_TorrentList\TorrentList()\Network_IO\AllPeers = 0 Tracker_FreePeerList() ; Удаление инфы о пирах. EndIf G_TorrentList\TorrentList()\Network\Error_Tracker=0 If AddElement(TaskTrackerList()) TaskTrackerList()\INFO_Hash = INFO_Hash TaskTrackerList()\Server = G_TorrentList\TorrentList()\Network\Tracker()\Address EndIf EndIf EndIf Next Break EndIf Next UnlockMutex(G_TorrentList\Mutex) If ListSize(TaskTrackerList())>0 If Test_LockMutex(G_ProgramMiscInfo\Network\TrackerTask_Mutex, 1000) = #True ResetList(G_ProgramMiscInfo\Network\TrackerTask_List()) ForEach TaskTrackerList() x=0 ForEach G_ProgramMiscInfo\Network\TrackerTask_List() If G_ProgramMiscInfo\Network\TrackerTask_List()\INFO_Hash = TaskTrackerList()\INFO_Hash And G_ProgramMiscInfo\Network\TrackerTask_List()\Server = TaskTrackerList()\Server ;x=1 ; Такое задание уже есть в списке. If G_ProgramMiscInfo\Network\TrackerTask_List()\Status = G_ProgramMiscInfo\Network\TrackerTask_List()\Status ; В очереди есть такое задание и дублировать нет смысла. x=1 EndIf Break EndIf Next If x=0 If AddElement(G_ProgramMiscInfo\Network\TrackerTask_List()) G_ProgramMiscInfo\Network\TrackerTask_List()\INFO_Hash = TaskTrackerList()\INFO_Hash G_ProgramMiscInfo\Network\TrackerTask_List()\Server = TaskTrackerList()\Server G_ProgramMiscInfo\Network\TrackerTask_List()\Status = Status G_ProgramMiscInfo\Network\TrackerTask_List()\Active = 0 EndIf EndIf Next UnlockMutex(G_ProgramMiscInfo\Network\TrackerTask_Mutex) SignalSemaphore(G_ProgramMiscInfo\Network\TrackerTask_Semaphore) EndIf EndIf EndIf EndIf EndProcedure ; При вызове этой процедуры должен быть захвачен мьютекс G_TorrentList\Mutex и выбран требуепмый торрент. Procedure Tracker_Completed(INFO_Hash.s) Protected NewList TaskTrackerList.ProgramStatus_Network_TrackerTaskList() Protected x.a ForEach G_TorrentList\TorrentList()\Network\Tracker() G_TorrentList\TorrentList()\Network\Tracker()\Command = #Tracker_Completed G_TorrentList\TorrentList()\Network\Tracker()\Error = 0 G_TorrentList\TorrentList()\Network\Tracker()\Left = G_TorrentList\TorrentList()\Torrent\Torrent_FileSize - G_TorrentList\TorrentList()\Torrent\CurrentFileSize G_TorrentList\TorrentList()\Network\Tracker()\Warning_Message_Err = 0 G_TorrentList\TorrentList()\Network\Tracker()\ErrorString = "" If AddElement(TaskTrackerList()) TaskTrackerList()\INFO_Hash = INFO_Hash TaskTrackerList()\Server = G_TorrentList\TorrentList()\Network\Tracker()\Address EndIf Next If ListSize(TaskTrackerList())>0 If Test_LockMutex(G_ProgramMiscInfo\Network\TrackerTask_Mutex, 1000) = #True ResetList(G_ProgramMiscInfo\Network\TrackerTask_List()) ForEach TaskTrackerList() x=0 ForEach G_ProgramMiscInfo\Network\TrackerTask_List() If G_ProgramMiscInfo\Network\TrackerTask_List()\INFO_Hash = TaskTrackerList()\INFO_Hash And G_ProgramMiscInfo\Network\TrackerTask_List()\Server = TaskTrackerList()\Server If G_ProgramMiscInfo\Network\TrackerTask_List()\Status = G_ProgramMiscInfo\Network\TrackerTask_List()\Status ; В очереди есть такое задание и дублировать нет смысла. x=1 EndIf Break EndIf Next If x=0 If AddElement(G_ProgramMiscInfo\Network\TrackerTask_List()) G_ProgramMiscInfo\Network\TrackerTask_List()\INFO_Hash = TaskTrackerList()\INFO_Hash G_ProgramMiscInfo\Network\TrackerTask_List()\Server = TaskTrackerList()\Server G_ProgramMiscInfo\Network\TrackerTask_List()\Status = #Tracker_Completed G_ProgramMiscInfo\Network\TrackerTask_List()\Active = 0 EndIf EndIf Next UnlockMutex(G_ProgramMiscInfo\Network\TrackerTask_Mutex) SignalSemaphore(G_ProgramMiscInfo\Network\TrackerTask_Semaphore) EndIf EndIf EndProcedure DisableExplicit ; IDE Options = PureBasic 5.11 (Windows - x86) ; Folding = ---- ; EnableXP