File: ssl_client.ml

package info (click to toggle)
ocamlnet 2.2.9-8
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 17,724 kB
  • ctags: 10,053
  • sloc: ml: 63,928; ansic: 1,973; makefile: 800; sh: 651
file content (112 lines) | stat: -rw-r--r-- 2,881 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#use "topfind";;
#require "equeue,equeue-ssl";;

(* This example connects stdin/stdout with a remote SSL service. To test
 * replace the following IP address and port with real numbers, e.g.
 * with an HTTPS server. Then start with
 *
 * ocaml ssl_client.ml
 *
 * Then enter something like:
 * 
 * GET / HTTP/1.0
 *
 * (+ double new lines).
 *)

let remote_ip_addr = "66.249.93.104" ;;  (* This is www.google.com *)
let remote_port = 443 ;;


let maybe_error err_opt =
  match err_opt with
    | None -> ()
    | Some err ->
	raise err
;;


let main() =
  Ssl.init();
  let esys = Unixqueue.create_unix_event_system() in
  let cl = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
  prerr_endline "* TCP connected";
  Unix.connect cl 
    (Unix.ADDR_INET
       (Unix.inet_addr_of_string remote_ip_addr, remote_port));
  
  let cl_ctx = Ssl.create_client_context Ssl.TLSv1 in
  let cl_mplex = 
    Uq_ssl.create_ssl_multiplex_controller cl cl_ctx esys in
  cl_mplex # start_ssl_connecting
    ~when_done:
    (fun err_opt ->
       maybe_error err_opt;
       prerr_endline "* SSL connected";
       
       let shutdown_in = ref (fun _ _ _ -> ()) in
       let shutdown_out = ref (fun _ _ _ -> ()) in

       let in_ch = 
	 new Uq_engines.input_async_mplex 
	   ~onshutdown:(`Action (fun ch m s -> !shutdown_in ch m s))
	   ~buffer_size:10
	   (cl_mplex :> Uq_engines.multiplex_controller) in
       let sender =
	 new Uq_engines.sender
	   ~src:in_ch
	   ~dst:Unix.stdout
	   ~close_dst:false
	   esys in
       
       let out_ch =
	 new Uq_engines.output_async_mplex
	   ~onshutdown:(`Action (fun ch m s -> !shutdown_out ch m s))
	   ~buffer_size:10
	   (cl_mplex :> Uq_engines.multiplex_controller) in
       let receiver =
	 new Uq_engines.receiver
	   ~src:Unix.stdin
	   ~dst:out_ch
	   ~close_src:false
	   esys in
       
       (* Shutdown actions: Because we have two channels attached to a
        * single multiplexer, we must synchronize the shutdown.
        *)
       shutdown_in := ( fun ch m s ->
			  (* The SSL connection is terminated. If the out_ch
                           * is already finished, we shut down the multiplexer.
                           * Else we simply abort the output channel.
                           *)
			  match out_ch # state with
			    | `Working _ ->
				out_ch # abort()
			    | _ ->
				m # start_shutting_down
				  ~when_done:(fun _ -> ()) ()
		      );
       shutdown_out := (fun ch m s ->
			  (* The terminal connection is terminated. Now we
                           * have to check whether in_ch is still alive.
                           *)
			  match in_ch # state with
			    | `Working _ ->
				in_ch # abort()
			    | _ ->
				m # start_shutting_down
				  ~when_done:(fun _ -> ()) ()
		       );

       ()
    )
    ();

  esys# run()
;;


(* Unixqueue.set_debug_mode true;*)
main();;

prerr_endline "DONE";