patch #7310
[mldonkey.git] / src / networks / donkey / donkeyProtoUdp.ml
blob95181bbcdb23cda947e9d99f4e72389d08bc5a50
1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
2 (*
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 open Printf2
21 open Md4
22 open Autoconf
23 open LittleEndian
24 open AnyEndian
26 open CommonTypes
27 open CommonGlobals
29 open DonkeyTypes
30 open DonkeyMftp
31 open Int64ops
33 module QueryReplyUdp = struct
35 type t = tagged_file list
37 let names_of_tag = file_common_tags
39 let get_file s pos =
40 let md4 = get_md4 s pos in
41 let ip = get_ip s (pos + 16) in
42 let port = get_port s (pos + 20) in
43 let tags, pos = get_tags s (pos+22) names_of_tag in
44 let file = {
45 f_md4 = md4;
46 f_ip = ip;
47 f_port = port;
48 f_tags = tags;
49 } in
50 file, pos
52 let parse len s =
53 let rec iter pos list =
54 if pos < len then
55 let file, pos = get_file s pos in
56 let pos = pos + 2 in
57 iter pos (file :: list)
58 else List.rev list
60 iter 1 []
62 let bprint oc t =
63 Printf.bprintf oc "FOUND:\n";
64 List.iter (fun t ->
65 Printf.bprintf oc "%s\n" (Md4.to_string t.f_md4);
66 Printf.bprintf oc "%s\n" (Ip.to_string t.f_ip);
67 Printf.bprintf oc "%d\n" t.f_port;
68 Printf.bprintf oc "TAGS:\n";
69 bprint_tags oc t.f_tags;
70 Printf.bprintf oc "\n"
71 ) t
73 let write buf t =
74 List.iter (fun file ->
75 buf_md4 buf file.f_md4;
76 buf_ip buf file.f_ip;
77 buf_port buf file.f_port;
78 buf_tags buf file.f_tags names_of_tag
79 ) t
81 end
83 module QueryCallUdp = struct
84 type t = {
85 ip : Ip.t;
86 port : int;
87 id : int64;
90 let parse len s =
91 let ip = get_ip s 1 in
92 let port = get_port s 5 in
93 let id = id_of_ip (get_ip s 7) in
94 { ip = ip; port = port; id = id; }
96 let bprint oc t =
97 Printf.bprintf oc "QueryCall %s : %d --> %Ld\n" (Ip.to_string t.ip)
98 t.port t.id
100 let write buf t =
101 buf_ip buf t.ip;
102 buf_port buf t.port;
103 buf_ip buf (ip_of_id t.id)
107 module PingServerUdp = struct (* client -> serveur pour identification ? *)
108 type t = int64
110 let parse len s =
112 get_uint64_32 s 1 (*, get_int8 s 2, get_int8 s 3*)
113 with _ -> 0L
115 let bprint oc t =
116 Printf.bprintf oc "PING %s\n" (Int64.to_string t)
118 let write buf t =
119 buf_int64_32 buf t
121 (* let bprint oc (t1,t2,t3) =
122 Printf.bprintf oc "MESSAGE 150 UDP %d %d %d\n" t1 t2 t3*)
124 (*let write buf (t1,t2,t3) =
125 buf_int8 buf t1;
126 buf_int8 buf t2;
127 buf_int8 buf t3;*)
131 module PingServerReplyUdp = struct (* reponse du serveur a 150 *)
133 type t = {
134 challenge : int64;
135 users : int64;
136 files : int64;
137 soft_limit : int64 option;
138 hard_limit : int64 option;
139 max_users : int64 option;
140 lowid_users : int64 option;
141 get_sources : bool;
142 get_files : bool;
143 newtags : bool;
144 unicode : bool;
145 get_sources2 : bool;
146 largefiles : bool;
147 udp_obfuscation : bool;
148 tcp_obfuscation : bool;
151 let parse len s =
152 let challenge = get_uint64_32 s 1 in
153 let users = get_uint64_32 s 5 in
154 let files = get_uint64_32 s 9 in
155 let max_users = if len >= 17 then Some (get_uint64_32 s 13) else None in
156 let soft_limit = if len >= 21 then Some (get_uint64_32 s 17) else None in
157 let hard_limit = if len >= 25 then Some (get_uint64_32 s 21) else None in
158 let flags = if len >= 29 then get_int s 25 else 0 in
159 let lowid_users = if len >= 33 then Some (get_uint64_32 s 29) else None in
162 challenge = challenge;
163 users = users;
164 files = files;
165 soft_limit = soft_limit;
166 hard_limit = hard_limit;
167 max_users = max_users;
168 lowid_users = lowid_users;
169 get_sources = 0x01 land flags = 0x01;
170 get_files = 0x02 land flags = 0x02;
171 newtags = 0x08 land flags = 0x08;
172 unicode = 0x10 land flags = 0x10;
173 get_sources2 = 0x20 land flags = 0x20;
174 largefiles = 0x100 land flags = 0x100;
175 udp_obfuscation = 0x200 land flags = 0x200;
176 tcp_obfuscation = 0x200 land flags = 0x200;
179 let bprint oc t =
180 Printf.bprintf oc "PING REPLY\n";
181 Printf.bprintf oc " %Ld users %Ld files\n" t.users t.files;
182 (match t.soft_limit with Some x -> Printf.bprintf oc " Soft limit: %Ld\n" x | None -> ());
183 (match t.hard_limit with Some x -> Printf.bprintf oc " Hard limit: %Ld\n" x | None -> ());
184 (match t.max_users with Some x -> Printf.bprintf oc " Max nusers: %Ld\n" x | None -> ());
185 (match t.lowid_users with Some x -> Printf.bprintf oc " LowId nusers: %Ld\n" x | None -> ());
186 Printf.bprintf oc " get_sources %b, get_files %b, newtags %b, unicode %b, get_sources2 %b, largefiles %b, udp_obfuscation %b, tcp_obfuscation %b"
187 t.get_sources t.get_files t.newtags t.unicode t.get_sources2 t.largefiles t.udp_obfuscation t.tcp_obfuscation
189 let write buf t =
190 buf_int64_32 buf t.challenge;
191 buf_int64_32 buf t.users;
192 buf_int64_32 buf t.files;
193 (match t.soft_limit, t.hard_limit, t.max_users with
194 None, None, None -> ()
195 | _ ->
196 buf_int64_32 buf (
197 match t.soft_limit with Some x -> x | None -> 0L);
198 buf_int64_32 buf (
199 match t.hard_limit with Some x -> x | None -> 0L);
200 buf_int64_32 buf (
201 match t.max_users with Some x -> x | None -> 0L)
205 module ServerDescUdp = struct
206 type t = int64
208 let invalid_len = Int64.of_int 0xF0FF
210 let parse len s = Int64.of_string s
212 let bprint b t =
213 Printf.bprintf b "ServerDescUdpReq\n"
216 // eserver 16.45+ supports a new OP_SERVER_DESC_RES answer, if the OP_SERVER_DESC_REQ contains a uint32
217 // challenge, the server returns additional info with OP_SERVER_DESC_RES. To properly distinguish the
218 // old and new OP_SERVER_DESC_RES answer, the challenge has to be selected carefully. The first 2 bytes
219 // of the challenge (in network byte order) MUST NOT be a valid string-len-int16!
222 let write buf t =
223 buf_int64_32 buf t
227 module ServerDescReplyUdp = struct
228 type t = {
229 name : string;
230 desc : string;
231 tags : tag list;
232 challenge : int64;
235 let names_of_tag = [
236 "\001", Field_KNOWN "servername";
237 "\011", Field_KNOWN "description";
238 "\012", Field_KNOWN "ping";
239 "\013", Field_KNOWN "fail";
240 "\014", Field_KNOWN "preference";
241 "\015", Field_KNOWN "port";
242 "\016", Field_KNOWN "ip";
243 "\133", Field_KNOWN "dynip";
244 "\135", Field_KNOWN "maxusers";
245 "\136", Field_KNOWN "softfiles";
246 "\137", Field_KNOWN "hardfiles";
247 "\144", Field_KNOWN "lastping";
248 "\145", Field_KNOWN "version";
249 "\146", Field_KNOWN "udpflags";
250 "\147", Field_KNOWN "auxportslist";
251 "\148", Field_KNOWN "lowidusers";
254 let parse1 len s challenge =
255 let name, pos = get_string s 1 in
256 let desc, pos = get_string s pos in
258 tags = [];
259 name = name;
260 desc = desc;
261 challenge = challenge;
264 let parse2 len s challenge =
265 let stags,pos = get_tags s 5 names_of_tag in
266 let name = ref "" in
267 let desc = ref "" in
268 List.iter (fun tag ->
269 match tag with
270 | { tag_name = Field_KNOWN "servername"; tag_value = String v } ->
271 name := v
272 | { tag_name = Field_KNOWN "description"; tag_value = String v } ->
273 desc := v
274 | _ -> ()
275 ) stags;
277 tags = stags;
278 name = !name;
279 desc = !desc;
280 challenge = challenge;
283 let parse len s =
284 let challenge = get_uint64_32 s 1 in
285 let test = right64 (left64 challenge 48) 48 in
286 let f = if test = ServerDescUdp.invalid_len then parse2 else parse1 in
287 f len s challenge
289 let bprint b t =
290 Printf.bprintf b "ServerDescReplyUdpReq\n";
291 Printf.bprintf b "name : %s\n" t.name;
292 Printf.bprintf b "desc : %s\n" t.desc
294 let write buf t =
295 buf_string buf t.name;
296 buf_string buf t.desc
300 module ServerListUdp = struct
301 type t = {
302 ip : Ip.t;
305 let parse len s =
307 let ip = get_ip s 1 in
309 ip = ip;
311 with _ ->
313 ip = Ip.null
316 let bprint b t =
317 Printf.bprintf b "ServerListUdp %s\n" (Ip.to_string t.ip)
319 let write buf t =
320 buf_ip buf t.ip
324 module QueryServersUdp = DonkeyProtoServer.QueryServers
325 module QueryServersReplyUdp = DonkeyProtoServer.QueryServersReply
326 module QueryLocationUdp = struct
327 open DonkeyProtoServer.QueryLocation
329 type t = Md4.t list
331 let parse len s =
332 let rec iter pos list =
333 if pos < len then
334 iter (pos+16) (get_md4 s pos :: list)
335 else
336 List.rev list
338 iter 1 []
340 let bprint b t =
341 Printf.bprintf b "UDP QUERY LOCATIONS: ";
342 List.iter (fun md4 -> Printf.bprintf b "%s " (Md4.to_string md4)) t
344 let write buf t =
345 List.iter (fun md4 -> buf_md4 buf md4) t
348 module QueryLocationUdpReq2 = struct
350 type t = (Md4.t * Int64.t) list
352 (* We never parse this anyway, it is outgoing only *)
353 let parse len s =
354 let rec iter pos list =
355 if pos < len then
356 iter (pos+20) ( (get_md4 s pos, get_uint64_32 s (pos+16)) :: list)
357 else
358 List.rev list
360 iter 1 []
362 let bprint b t =
363 Printf.bprintf b "UDP QUERY LOCATIONS2: ";
364 List.iter (fun (md4,size) -> Printf.bprintf b "%s|%Ld " (Md4.to_string md4) size) t;
365 Printf.bprintf b "\n"
367 let write buf t =
368 List.iter (fun (md4,size) -> buf_md4 buf md4; buf_int64_32 buf size) t
372 module QueryLocationReplyUdp = struct
373 open DonkeyProtoServer.QueryLocationReply
375 type t = DonkeyProtoServer.QueryLocationReply.t list
377 let parse len s =
378 let rec iter_len pos list =
379 if pos < len then
380 let md4 = get_md4 s pos in
381 let n = get_uint8 s (pos+16) in
382 let rec iter i =
383 if i = n then [] else
384 let ip = get_ip s (pos+17 + i * 6) in
385 let port = get_port s (pos+21+ i * 6) in
386 { ip = ip; port = port; } :: (iter (i+1))
388 let locs = iter 0 in
389 let pos = pos+17+6*n + 2 in
390 iter_len pos ({ locs =locs; md4 = md4 } :: list)
391 else
392 List.rev list
394 iter_len 1 []
396 let bprint b t =
397 Printf.bprintf b "UDP LOCATION: %d\n" (List.length t);
398 List.iter (fun t ->
399 Printf.bprintf b " of %s:\n" (Md4.to_string t.md4);
400 List.iter (fun l ->
401 Printf.bprintf b "%s:%d " (Ip.to_string l.ip) l.port;
402 ) t.locs;
403 Printf.bprintf b "\n") t
405 let write buf t =
406 List.iter (fun t ->
407 buf_md4 buf t.md4;
408 buf_int8 buf (List.length t.locs);
409 List.iter (fun l ->
410 buf_ip buf l.ip;
411 buf_port buf l.port;
412 ) t.locs
418 module QueryUdp = DonkeyProtoServer.Query
421 let parse len s =
422 let rec iter list pos =
423 if len > pos then
424 let t, pos = parse_query s pos in
425 iter (t :: list) pos
426 else List.rev list
428 iter [] 1
430 let bprint b t =
431 Printf.bprintf b "UDP QUERY: %d\n" (List.length t);
432 List.iter (bprint_query b) t
434 let write buf t =
435 List.iter write t
440 module QueryIDReplyUdp = DonkeyProtoServer.QueryIDReply
442 type t =
443 | QueryServersUdpReq of QueryServersUdp.t
444 | QueryServersReplyUdpReq of QueryServersReplyUdp.t
446 | PingServerUdpReq of PingServerUdp.t
447 | PingServerReplyUdpReq of PingServerReplyUdp.t
449 | QueryLocationUdpReq2 of QueryLocationUdpReq2.t
450 | QueryLocationUdpReq of QueryLocationUdp.t
451 | QueryLocationReplyUdpReq of QueryLocationReplyUdp.t
453 | QueryReplyUdpReq of QueryReplyUdp.t
454 | QueryUdpReq of CommonTypes.query
455 | QueryMultipleUdpReq of CommonTypes.query
456 | QueryCallUdpReq of QueryCallUdp.t
457 | QueryIDReplyUdpReq of QueryIDReplyUdp.t
458 | FileGroupInfoUdpReq of QueryLocationReplyUdp.t
459 | ServerDescUdpReq of ServerDescUdp.t
460 | ServerDescReplyUdpReq of ServerDescReplyUdp.t
461 | ServerListUdpReq of ServerListUdp.t
463 | EmuleReaskFilePingUdpReq of Md4.t
464 | EmuleReaskAckUdpReq of Md4.t
465 | EmuleFileNotFoundUdpReq
466 | EmuleQueueFullUdpReq
467 | EmulePortTestReq
469 | UnknownUdpReq of int * string
471 let parse magic s =
473 let len = String.length s in
474 if len = 0 then raise Not_found;
475 let opcode = int_of_char (s.[0]) in
476 (* lprintf "opcode: %d" opcode; lprint_newline (); *)
477 match opcode with
478 | 150 -> PingServerUdpReq (PingServerUdp.parse len s)
479 | 151 -> PingServerReplyUdpReq (PingServerReplyUdp.parse len s)
481 | 146 -> QueryMultipleUdpReq (QueryUdp.parse len s)
482 | 152 -> QueryUdpReq (QueryUdp.parse len s)
483 | 153 -> QueryReplyUdpReq (QueryReplyUdp.parse len s)
484 | 154 -> QueryLocationUdpReq (QueryLocationUdp.parse len s)
485 | 155 -> QueryLocationReplyUdpReq (QueryLocationReplyUdp.parse len s)
486 | 156 -> QueryCallUdpReq (QueryCallUdp.parse len s)
487 | 160 -> QueryServersUdpReq (QueryServersUdp.parse len s)
488 | 161 -> QueryServersReplyUdpReq (QueryServersReplyUdp.parse len s)
489 | 162 -> ServerDescUdpReq (ServerDescUdp.parse len s)
490 | 163 -> ServerDescReplyUdpReq (ServerDescReplyUdp.parse len s)
491 | 164 -> ServerListUdpReq (ServerListUdp.parse len s)
493 | 144 -> EmuleReaskFilePingUdpReq (get_md4 s 1)
494 | 145 -> EmuleReaskAckUdpReq (get_md4 s 1)
495 (* | 146 -> EmuleFileNotFoundUdpReq *)
496 | 147 -> EmuleQueueFullUdpReq
497 | 254 -> EmulePortTestReq
499 | _ -> raise Exit
500 with
501 e ->
502 lprintf "From UDP:\n";
503 dump s;
504 UnknownUdpReq (magic, s)
506 let print t =
507 let b = Buffer.create 100 in
508 begin
509 match t with
511 | QueryUdpReq t -> QueryUdp.bprint b t
512 | QueryMultipleUdpReq t -> QueryUdp.bprint b t
513 | QueryReplyUdpReq t -> QueryReplyUdp.bprint b t
514 | QueryLocationUdpReq2 t -> QueryLocationUdpReq2.bprint b t
515 | QueryLocationUdpReq t -> QueryLocationUdp.bprint b t
516 | QueryLocationReplyUdpReq t
517 | FileGroupInfoUdpReq t -> QueryLocationReplyUdp.bprint b t
518 | QueryCallUdpReq t -> QueryCallUdp.bprint b t
520 | QueryServersUdpReq t -> QueryServersUdp.bprint b t
521 | QueryServersReplyUdpReq t -> QueryServersReplyUdp.bprint b t
522 | QueryIDReplyUdpReq t -> QueryIDReplyUdp.bprint b t
524 | PingServerUdpReq t -> PingServerUdp.bprint b t
525 | PingServerReplyUdpReq t -> PingServerReplyUdp.bprint b t
526 | ServerDescUdpReq t -> ServerDescUdp.bprint b t
527 | ServerDescReplyUdpReq t -> ServerDescReplyUdp.bprint b t
528 | ServerListUdpReq t -> ServerListUdp.bprint b t
530 | EmuleReaskFilePingUdpReq md4 ->
531 Printf.bprintf b "EmuleReaskFilePingUdpReq %s" (Md4.to_string md4)
532 | EmuleReaskAckUdpReq md4 ->
533 Printf.bprintf b "EmuleReaskAckUdpReq %s" (Md4.to_string md4)
534 | EmuleFileNotFoundUdpReq ->
535 Printf.bprintf b "EmuleFileNotFoundUdpReq"
536 | EmuleQueueFullUdpReq ->
537 Printf.bprintf b "EmuleQueueFullUdpReq"
538 | EmulePortTestReq ->
539 Printf.bprintf b "EmulePortTestReq"
541 | UnknownUdpReq (magic, s) ->
542 Printf.bprintf b "UnknownReq magic %d\n" magic;
543 bdump b s;
544 end;
545 Printf.bprintf b "\n";
546 Buffer.contents b
548 let write buf t =
549 match t with
551 | UnknownUdpReq (magic, s) ->
552 buf_int8 buf magic;
553 Buffer.add_string buf s
555 | EmuleReaskFilePingUdpReq md4 ->
556 buf_int8 buf 197;
557 buf_int8 buf 145;
558 buf_md4 buf md4
560 | EmuleReaskAckUdpReq md4 ->
561 buf_int8 buf 197;
562 buf_int8 buf 145;
563 buf_md4 buf md4
565 | EmuleFileNotFoundUdpReq ->
566 buf_int8 buf 197;
567 buf_int8 buf 146
569 | EmuleQueueFullUdpReq ->
570 buf_int8 buf 197;
571 buf_int8 buf 147
573 | _ ->
574 buf_int8 buf 227;
575 match t with
576 | QueryServersUdpReq t ->
577 buf_int8 buf 160;
578 QueryServersUdp.write buf t
579 | QueryServersReplyUdpReq t ->
580 buf_int8 buf 161;
581 QueryServersReplyUdp.write buf t
583 | ServerDescUdpReq t ->
584 buf_int8 buf 162;
585 ServerDescUdp.write buf t
586 | ServerDescReplyUdpReq t ->
587 buf_int8 buf 163;
588 ServerDescReplyUdp.write buf t
589 | ServerListUdpReq t ->
590 buf_int8 buf 164;
591 ServerListUdp.write buf t
593 | PingServerUdpReq t ->
594 buf_int8 buf 150;
595 PingServerUdp.write buf t
596 | PingServerReplyUdpReq t ->
597 buf_int8 buf 151;
598 PingServerReplyUdp.write buf t
600 | QueryLocationUdpReq t ->
601 buf_int8 buf 154;
602 QueryLocationUdp.write buf t
603 | QueryLocationUdpReq2 t ->
604 buf_int8 buf 148;
605 QueryLocationUdpReq2.write buf t
606 | QueryLocationReplyUdpReq t ->
607 buf_int8 buf 155;
608 QueryLocationReplyUdp.write buf t
609 | QueryUdpReq t ->
610 buf_int8 buf 152;
611 QueryUdp.write buf t
612 | QueryMultipleUdpReq t ->
613 buf_int8 buf 146;
614 QueryUdp.write buf t
615 | QueryReplyUdpReq t ->
616 buf_int8 buf 153;
617 QueryReplyUdp.write buf t
618 | QueryCallUdpReq t ->
619 buf_int8 buf 156;
620 QueryCallUdp.write buf t
621 | FileGroupInfoUdpReq t ->
622 buf_int8 buf 251;
623 QueryLocationReplyUdp.write buf t
625 | QueryIDReplyUdpReq t ->
626 buf_int8 buf 53;
627 QueryIDReplyUdp.write buf t
629 | EmulePortTestReq ->
630 buf_int8 buf 2;
631 buf_int8 buf 0;
632 buf_int8 buf 0;
633 buf_int8 buf 0;
634 buf_int8 buf 0xfe;
635 buf_int8 buf 0x31
637 | EmuleQueueFullUdpReq
638 | EmuleFileNotFoundUdpReq
639 | EmuleReaskAckUdpReq _
640 | EmuleReaskFilePingUdpReq _
641 | UnknownUdpReq _ -> assert false