2
2
High-level interface to libuv's TCP functionality
3
3
" ] ;
4
4
5
- #[ cfg( ignore) ]
5
+ import ip = net_ip;
6
+
7
+ export tcp_connect_result;
8
+ export connect;
9
+
10
+ enum tcp_socket {
11
+ valid_tcp_socket( @tcp_socket_data )
12
+ }
13
+
14
+ enum tcp_connect_result {
15
+ tcp_connected( tcp_socket ) ,
16
+ tcp_connect_error( uv:: ll:: uv_err_data )
17
+ }
18
+
19
+ #[ doc="
20
+ Initiate a client connection over TCP/IP
21
+
22
+ # Arguments
23
+
24
+ * ip - The IP address (versions 4 or 6) of the remote host
25
+ * port - the unsigned integer of the desired remote host port
26
+
27
+ # Returns
28
+
29
+ A `tcp_connect_result` that can be used to determine the connection and,
30
+ if successful, send and receive data to/from the remote host
31
+ " ]
32
+ fn connect ( input_ip : ip:: ip_addr , port : uint ) -> tcp_connect_result unsafe {
33
+ let result_po = comm:: port :: < conn_attempt > ( ) ;
34
+ let closed_signal_po = comm:: port :: < ( ) > ( ) ;
35
+ let conn_data = {
36
+ result_ch: comm:: chan ( result_po) ,
37
+ closed_signal_ch: comm:: chan ( closed_signal_po)
38
+ } ;
39
+ let conn_data_ptr = ptr:: addr_of ( conn_data) ;
40
+ let socket_data = @{
41
+ reader_port: comm:: port :: < [ u8 ] > ( ) ,
42
+ stream_handle : uv:: ll:: tcp_t ( ) ,
43
+ connect_req : uv:: ll:: connect_t ( ) ,
44
+ write_req : uv:: ll:: write_t ( )
45
+ } ;
46
+ log ( debug, #fmt ( "tcp_connect result_ch %?" , conn_data. result_ch ) ) ;
47
+ // get an unsafe representation of our stream_handle_ptr that
48
+ // we can send into the interact cb to be handled in libuv..
49
+ let socket_data_ptr: * tcp_socket_data =
50
+ ptr:: addr_of ( * socket_data) ;
51
+ // in we go!
52
+ let hl_loop = uv:: global_loop:: get ( ) ;
53
+ log ( debug, #fmt ( "stream_handl_ptr outside interact %?" ,
54
+ ptr:: addr_of ( ( * socket_data_ptr) . stream_handle ) ) ) ;
55
+ uv:: hl:: interact ( hl_loop) { |loop_ptr|
56
+ log ( debug, "in interact cb for tcp client connect.." ) ;
57
+ let stream_handle_ptr =
58
+ ptr:: addr_of ( ( * socket_data_ptr) . stream_handle ) ;
59
+ log ( debug, #fmt ( "stream_handl_ptr in interact %?" ,
60
+ stream_handle_ptr) ) ;
61
+ alt uv:: ll:: tcp_init ( loop_ptr, stream_handle_ptr) {
62
+ 0i32 {
63
+ log ( debug, "tcp_init successful" ) ;
64
+ alt input_ip {
65
+ ipv4 {
66
+ log( debug, "dealing w/ ipv4 connection.." ) ;
67
+ let tcp_addr = ipv4_ip_addr_to_sockaddr_in ( input_ip,
68
+ port) ;
69
+ let tcp_addr_ptr = ptr:: addr_of ( tcp_addr) ;
70
+ let connect_req_ptr =
71
+ ptr:: addr_of ( ( * socket_data_ptr) . connect_req ) ;
72
+ alt uv:: ll:: tcp_connect (
73
+ connect_req_ptr,
74
+ stream_handle_ptr,
75
+ tcp_addr_ptr,
76
+ tcp_connect_on_connect_cb) {
77
+ 0i32 {
78
+ log ( debug, "tcp_connect successful" ) ;
79
+ // reusable data that we'll have for the
80
+ // duration..
81
+ uv:: ll:: set_data_for_uv_handle ( stream_handle_ptr,
82
+ socket_data_ptr) ;
83
+ // just so the connect_cb can send the
84
+ // outcome..
85
+ uv:: ll:: set_data_for_req ( connect_req_ptr,
86
+ conn_data_ptr) ;
87
+ log ( debug, "leaving tcp_connect interact cb..." ) ;
88
+ // let tcp_connect_on_connect_cb send on
89
+ // the result_ch, now..
90
+ }
91
+ _ {
92
+ // immediate connect failure.. probably a garbage
93
+ // ip or somesuch
94
+ let err_data = uv:: ll:: get_last_err_data ( loop_ptr) ;
95
+ comm:: send ( ( * conn_data_ptr) . result_ch ,
96
+ conn_failure ( err_data) ) ;
97
+ uv:: ll:: set_data_for_uv_handle ( stream_handle_ptr,
98
+ conn_data_ptr) ;
99
+ uv:: ll:: close ( stream_handle_ptr, stream_error_close_cb) ;
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ _ {
106
+ // failure to create a tcp handle
107
+ let err_data = uv:: ll:: get_last_err_data ( loop_ptr) ;
108
+ comm:: send ( ( * conn_data_ptr) . result_ch ,
109
+ conn_failure ( err_data) ) ;
110
+ }
111
+ }
112
+ } ;
113
+ alt comm:: recv ( result_po) {
114
+ conn_success {
115
+ log( debug, "tcp::connect - received success on result_po" ) ;
116
+ tcp_connected ( valid_tcp_socket ( socket_data) )
117
+ }
118
+ conn_failure ( err_data) {
119
+ comm:: recv ( closed_signal_po) ;
120
+ log ( debug, "tcp::connect - received failure on result_po" ) ;
121
+ tcp_connect_error ( err_data)
122
+ }
123
+ }
124
+ }
125
+ // INTERNAL API
126
+ type connect_req_data = {
127
+ result_ch : comm:: chan < conn_attempt > ,
128
+ closed_signal_ch : comm:: chan < ( ) >
129
+ } ;
130
+
131
+ crust fn stream_error_close_cb ( handle : * uv:: ll:: uv_tcp_t ) unsafe {
132
+ let data = uv:: ll:: get_data_for_uv_handle ( handle) as
133
+ * connect_req_data ;
134
+ comm:: send ( ( * data) . closed_signal_ch , ( ) ) ;
135
+ log ( debug, #fmt ( "exiting steam_error_close_cb for %?" , handle) ) ;
136
+ }
137
+
138
+ crust fn tcp_connect_close_cb ( handle : * uv:: ll:: uv_tcp_t ) unsafe {
139
+ log ( debug, #fmt ( "closed client tcp handle %?" , handle) ) ;
140
+ }
141
+
142
+ crust fn tcp_connect_on_connect_cb ( connect_req_ptr : * uv:: ll:: uv_connect_t ,
143
+ status : libc:: c_int ) unsafe {
144
+ let conn_data_ptr = ( uv:: ll:: get_data_for_req ( connect_req_ptr)
145
+ as * connect_req_data ) ;
146
+ let result_ch = ( * conn_data_ptr) . result_ch ;
147
+ log ( debug, #fmt ( "tcp_connect result_ch %?" , result_ch) ) ;
148
+ let tcp_stream_ptr =
149
+ uv:: ll:: get_stream_handle_from_connect_req ( connect_req_ptr) ;
150
+ alt status {
151
+ 0i32 {
152
+ log( debug, "successful tcp connection!" ) ;
153
+ comm:: send ( result_ch, conn_success) ;
154
+ }
155
+ _ {
156
+ log( debug, "error in tcp_connect_on_connect_cb" ) ;
157
+ let loop_ptr = uv:: ll:: get_loop_for_uv_handle ( tcp_stream_ptr) ;
158
+ let err_data = uv:: ll:: get_last_err_data ( loop_ptr) ;
159
+ log ( debug, #fmt ( "err_data %? %?" , err_data. err_name ,
160
+ err_data. err_msg ) ) ;
161
+ comm:: send ( result_ch, conn_failure ( err_data) ) ;
162
+ uv:: ll:: set_data_for_uv_handle ( tcp_stream_ptr,
163
+ conn_data_ptr) ;
164
+ uv:: ll:: close ( tcp_stream_ptr, stream_error_close_cb) ;
165
+ }
166
+ }
167
+ log ( debug, "leaving tcp_connect_on_connect_cb" ) ;
168
+ }
169
+
170
+ enum conn_attempt {
171
+ conn_success,
172
+ conn_failure( uv:: ll:: uv_err_data )
173
+ }
174
+
175
+
176
+ type tcp_socket_data = {
177
+ reader_port : comm:: port < [ u8 ] > ,
178
+ stream_handle : uv:: ll:: uv_tcp_t ,
179
+ connect_req : uv:: ll:: uv_connect_t ,
180
+ write_req : uv:: ll:: uv_write_t
181
+ } ;
182
+
183
+ // convert rust ip_addr to libuv's native representation
184
+ fn ipv4_ip_addr_to_sockaddr_in ( input : ip:: ip_addr ,
185
+ port : uint ) -> uv:: ll:: sockaddr_in unsafe {
186
+ uv:: ll:: ip4_addr ( ip:: format_addr ( input) , port as int )
187
+ }
188
+
189
+ #[ cfg( test) ]
6
190
mod test {
7
191
#[ test]
8
192
fn test_gl_tcp_ipv4_request ( ) {
9
- let ip = "127.0.0.1" ;
193
+ let ip_str = "127.0.0.1" ;
10
194
let port = 80 u;
11
195
let expected_read_msg = "foo" ;
12
196
let actual_write_msg = "bar" ;
13
- let addr = ipv4 :: address ( ip , port ) ;
197
+ let host_ip = ip :: v4 :: parse_addr ( ip_str ) ;
14
198
15
199
let data_po = comm:: port :: < [ u8 ] > ( ) ;
16
200
let data_ch = comm:: chan ( data_po) ;
17
201
18
- alt connect( addr) {
19
- tcp_connected ( tcp_stream) {
202
+ alt connect( host_ip, port) {
203
+ tcp_connected ( sock) {
204
+ log ( debug, "successful tcp connect" ) ;
205
+ /*
20
206
let write_data = str::as_buf(actual_write_msg);
21
- alt write( tcp_stream , [ write_data] ) {
207
+ alt write(sock , [write_data]) {
22
208
tcp_write_success {
23
- let mut total_read_data : [ u8] = [ ]
24
- let reader_po = read_start ( tcp_stream ) ;
209
+ let mut total_read_data: [u8] = [];
210
+ let reader_po = read_start(sock);nyw
25
211
loop {
26
212
alt comm::recv(reader_po) {
27
213
new_read_data(data) {
@@ -36,7 +222,8 @@ mod test {
36
222
break;
37
223
}
38
224
error {
39
- fail "erroring occured during read attempt.. FIXME need info" ;
225
+ fail "erroring occured during read attempt.."
226
+ + "FIXME need info";
40
227
}
41
228
}
42
229
}
@@ -46,9 +233,13 @@ mod test {
46
233
fail "error during write attempt.. FIXME need err info";
47
234
}
48
235
}
236
+ */
49
237
}
50
- tcp_connect_error {
51
- fail "error during connection attempt.. FIXME need err info.." ;
238
+ tcp_connect_error ( err_data) {
239
+ log ( debug, "tcp_connect_error received.." ) ;
240
+ log ( debug, #fmt ( "tcp connect error: %? %?" , err_data. err_name ,
241
+ err_data. err_msg ) ) ;
242
+ assert false;
52
243
}
53
244
}
54
245
0 commit comments