46
69
let prerr_command cmd =
48
Telnet_data s -> prerr_endline ("Telnet: Data " ^ s)
49
| Telnet_nop -> prerr_endline "Telnet: NOP";
50
| Telnet_dm -> prerr_endline "Telnet: DM";
51
| Telnet_brk -> prerr_endline "Telnet: BRK";
52
| Telnet_ip -> prerr_endline "Telnet: IP";
53
| Telnet_ao -> prerr_endline "Telnet: AO";
54
| Telnet_ayt -> prerr_endline "Telnet: AYT";
55
| Telnet_ec -> prerr_endline "Telnet: EC";
56
| Telnet_el -> prerr_endline "Telnet: EL";
57
| Telnet_ga -> prerr_endline "Telnet: GA";
58
| Telnet_sb c -> prerr_endline ("Telnet: DB " ^
59
string_of_int(Char.code c));
60
| Telnet_se -> prerr_endline "Telnet: SE";
61
| Telnet_will c -> prerr_endline ("Telnet: WILL " ^
62
string_of_int(Char.code c));
63
| Telnet_wont c -> prerr_endline ("Telnet: WONT " ^
64
string_of_int(Char.code c));
65
| Telnet_do c -> prerr_endline ("Telnet: DO " ^
66
string_of_int(Char.code c));
67
| Telnet_dont c -> prerr_endline ("Telnet: DONT " ^
68
string_of_int(Char.code c));
69
| Telnet_unknown c -> prerr_endline ("Telnet: unknown command " ^
70
string_of_int(Char.code c));
71
| Telnet_eof -> prerr_endline "Telnet: <eof>";
72
| Telnet_timeout -> prerr_endline "Telnet: <timeout>";
71
Telnet_data s -> dlog ("command: Data " ^ s)
72
| Telnet_nop -> dlog "command: NOP";
73
| Telnet_dm -> dlog "command: DM";
74
| Telnet_brk -> dlog "command: BRK";
75
| Telnet_ip -> dlog "command: IP";
76
| Telnet_ao -> dlog "command: AO";
77
| Telnet_ayt -> dlog "command: AYT";
78
| Telnet_ec -> dlog "command: EC";
79
| Telnet_el -> dlog "command: EL";
80
| Telnet_ga -> dlog "command: GA";
81
| Telnet_sb c -> dlog ("command: DB " ^
82
string_of_int(Char.code c));
83
| Telnet_se -> dlog "command: SE";
84
| Telnet_will c -> dlog ("command: WILL " ^
85
string_of_int(Char.code c));
86
| Telnet_wont c -> dlog ("command: WONT " ^
87
string_of_int(Char.code c));
88
| Telnet_do c -> dlog ("command: DO " ^
89
string_of_int(Char.code c));
90
| Telnet_dont c -> dlog ("command: DONT " ^
91
string_of_int(Char.code c));
92
| Telnet_unknown c -> dlog ("command: unknown command " ^
93
string_of_int(Char.code c));
94
| Telnet_eof -> dlog "command: <eof>";
95
| Telnet_timeout -> dlog "command: <timeout>";
474
self # connect_server;
475
(* 'group' must not be set earlier, because it is used as
476
* indicator whether a connection is established or not.
479
let timeout_value = options.connection_timeout in
480
Unixqueue.add_resource esys g (Unixqueue.Wait_in socket,
482
Unixqueue.add_close_action esys g (socket,
483
(fun _ -> self # shutdown));
484
Unixqueue.add_handler esys g (self # handler);
486
self # maintain_polling;
488
Unix.Unix_error(_,_,_) as x -> exn_handler x
489
| Sys_error _ as x -> exn_handler x
494
self # connect_server
496
dlog "Telnet connection: Connected!";
497
(* 'group' must not be set earlier, because it is used as
498
* indicator whether a connection is established or not.
501
let timeout_value = options.connection_timeout in
502
Unixqueue.add_resource esys g (Unixqueue.Wait_in socket,
504
Unixqueue.add_handler esys g (self # handler);
506
self # maintain_polling
509
dlog "Telnet connection: Connection error!";
511
method private inet_addr hostname =
513
(* TODO: 'inet_addr_of_string' may block *)
514
syscall (fun () -> Unix.inet_addr_of_string hostname)
518
let h = syscall (fun () -> Unix.gethostbyname hostname) in
519
h.Unix.h_addr_list.(0)
523
("Telnet_client: host name lookup failed for " ^ hostname));
526
method private connect_server =
533
method expect_input flag =
536
failwith "Telnet_client: not attached"
538
Unixqueue.remove_resource esys g (Unixqueue.Wait_in socket);
541
options.connection_timeout
544
Unixqueue.add_resource esys g (Unixqueue.Wait_in socket,
548
method private connect_server f_ok f_err =
528
550
begin match connector with
529
Telnet_connect(hostname, port) ->
530
if options.verbose_connection then
531
prerr_endline ("Telnet connection: Connecting to server " ^
534
let addr = self # inet_addr hostname in
536
let dom = Netsys.domain_of_inet_addr addr in
538
(fun () -> Unix.socket dom Unix.SOCK_STREAM 0) in
539
(* Connect in non-blocking mode: *)
540
syscall (fun () -> Unix.set_nonblock s);
541
(* Urgent data is received inline: *)
542
syscall (fun () -> Unix.setsockopt s Unix.SO_OOBINLINE true);
544
syscall (fun () -> Unix.connect s (Unix.ADDR_INET (addr, port)));
546
if options.verbose_connection then
547
prerr_endline "Telnet connection: Connected!";
549
Unix.Unix_error(Unix.EINPROGRESS,_,_) ->
550
(* The 'connect' has not yet been finished. *)
552
(* The 'connect' operation continues in the background.
553
* It is guaranteed that the socket becomes writeable if
554
* the connection is established.
555
* (Of course, it becomes readable if there is already data
556
* to read, but if the other side does not send us anything
557
* only writeability is indicated.)
558
* If the connection fails: This situation is not very well
559
* described in the manual pages. The "Single Unix Spec"
560
* says nothing about this case. In the Linux manpages I
561
* found that it is possible to read the O_ERROR socket option
562
* (see connect(2)). By experience I found out that the socket
563
* indicates readability, and that the following "read"
564
* syscall then reports the error correctly.
565
* The O_ERROR socket option is not supported by O'Caml, so
566
* the latter is assumed.
569
syscall (fun () -> Unix.close s);
551
| Telnet_connect(hostname, port) ->
552
dlog ("Telnet connection: Connecting to server " ^
555
let g1 = Unixqueue.new_group esys in
559
(`Socket(`Sock_inet_byname(Unix.SOCK_STREAM,
562
Uq_engines.default_connect_options))
565
connecting <- Some eng;
567
Uq_engines.when_state
570
Unixqueue.clear esys g1;
575
Unix.setsockopt s Unix.SO_OOBINLINE true);
576
Netlog.Debug.track_fd
577
~owner:"Telnet_client"
578
~descr:("connection to " ^
579
hostname ^ ":" ^ string_of_int port)
586
Unixqueue.clear esys g1;
590
~is_aborted:(fun () ->
591
Unixqueue.clear esys g1;
595
let timeout_value = options.connection_timeout in
596
Unixqueue.once esys g1 timeout_value eng#abort
575
598
| Telnet_socket s ->
577
600
syscall(fun () -> Unix.setsockopt s Unix.SO_OOBINLINE true);
579
if options.verbose_connection then
580
prerr_endline "Telnet connection: Got connected socket";
602
Netlog.Debug.track_fd
603
~owner:"Telnet_client"
604
~descr:("connection to " ^
605
try Netsys.string_of_sockaddr(Netsys.getpeername s)
606
with _ -> "(noaddr)")
608
dlog "Telnet connection: Got connected socket";
609
let g1 = Unixqueue.new_group esys in
610
Unixqueue.once esys g1 0.0 f_ok
583
613
socket_state <- Up_rw;
676
method private check_connection =
677
(* You need to call this method only if 'connecting' is true, and of
678
* course if the socket is either readable or writeable.
679
* The socket is set to blocking mode, again. The connect time
680
* is measured and recorded.
681
* TODO: find out if a socket error happened in the meantime.
683
if connecting then begin
684
syscall(fun () -> Unix.clear_nonblock socket);
686
if options.verbose_connection then
687
prerr_endline "Telnet connection: Got connection status";
691
704
method private handler _ _ ev =
692
705
let g = match group with
764
776
input_timed_out <- false;
766
if options.verbose_connection then
767
prerr_endline "Telnet connection: Input event!";
778
dlog "Telnet connection: Input event!";
769
780
let _g = match group with
771
782
| None -> assert false
775
self # check_connection;
777
785
(* Read data into the primary_buffer *)
782
Unix.read socket primary_buffer 0 (String.length primary_buffer)) in
793
socket primary_buffer 0 (String.length primary_buffer) in
796
| Unix.Unix_error(Unix.EAGAIN,_,_) ->
785
800
Netbuffer.add_sub_string input_buffer primary_buffer 0 n;
1053
1063
if q == synch_queue then begin
1054
1064
sending_urgent_data <- true;
1055
if options.verbose_connection then
1056
prerr_endline "Sending urgent data";
1065
dlog "Sending urgent data";
1059
1068
sending_urgent_data <- false;
1061
if options.verbose_output then begin
1062
prerr_endline "Telnet output queue:";
1070
if !Debug.enable && options.verbose_output then begin
1071
dlog "Telnet output queue:";
1063
1072
Queue.iter prerr_command output_queue;
1064
prerr_endline "Telnet: <end of queue>";
1073
dlog "<end of queue>";
1067
1076
try copy() with Queue.Empty -> ()
1077
Unix.send socket (Netbuffer.unsafe_buffer output_buffer) 0 l flags) in
1088
socket (Netbuffer.unsafe_buffer output_buffer) 0 l flags
1090
| Unix.Unix_error(Unix.EAGAIN,_,_) -> 0
1078
1092
Netbuffer.delete output_buffer 0 k;
1081
if Netbuffer.length output_buffer = 0 & send_eof then begin
1082
if options.verbose_connection then
1083
prerr_endline "Telnet connection: Sending EOF";
1095
if Netbuffer.length output_buffer = 0 && send_eof then begin
1096
dlog "Telnet connection: Sending EOF";
1084
1097
syscall(fun () -> Unix.shutdown socket Unix.SHUTDOWN_SEND);
1085
1098
socket_state <- Up_r;