win32-pipe 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +51 -46
- data/MANIFEST +17 -15
- data/README +52 -55
- data/Rakefile +68 -48
- data/examples/example_client.rb +29 -29
- data/examples/example_client_async.rb +82 -82
- data/examples/example_server.rb +32 -32
- data/examples/example_server_async.rb +100 -100
- data/lib/win32/pipe.rb +251 -254
- data/lib/win32/pipe/client.rb +65 -65
- data/lib/win32/pipe/server.rb +96 -96
- data/lib/win32/pipe/windows/constants.rb +37 -0
- data/lib/win32/pipe/windows/functions.rb +31 -0
- data/test/test_win32_pipe.rb +162 -126
- data/test/test_win32_pipe_client.rb +62 -60
- data/test/test_win32_pipe_server.rb +34 -34
- data/win32-pipe.gemspec +25 -25
- metadata +22 -10
data/examples/example_server.rb
CHANGED
@@ -1,33 +1,33 @@
|
|
1
|
-
#########################################################################
|
2
|
-
# example_server.rb
|
3
|
-
#
|
4
|
-
# A simple named pipe server. Start this up in its own terminal window.
|
5
|
-
# You may have to use the task manager to kill it if you don't connect
|
6
|
-
# with the test client program.
|
7
|
-
#
|
8
|
-
# You can start this server with the 'rake example_server' task. Modify
|
9
|
-
# this code as you see fit.
|
10
|
-
#########################################################################
|
11
|
-
require 'win32/pipe'
|
12
|
-
include Win32
|
13
|
-
|
14
|
-
Thread.new { loop { sleep 0.01 } } # Allow Ctrl-C
|
15
|
-
|
16
|
-
puts "VERSION: " + Pipe::VERSION
|
17
|
-
|
18
|
-
# Block form
|
19
|
-
Pipe::Server.new('foo') do |pipe|
|
20
|
-
pipe.connect
|
21
|
-
data = pipe.read
|
22
|
-
puts "Got [#{data}]"
|
23
|
-
pipe.write "Thanks for the data!"
|
24
|
-
end
|
25
|
-
|
26
|
-
# Non-block form
|
27
|
-
#pserver = Pipe::Server.new('foo')
|
28
|
-
#pserver.connect # put server in wait connect
|
29
|
-
#data = pserver.read
|
30
|
-
#puts "Got [#{data}]"
|
31
|
-
#pserver.write("Thanks for the data!")
|
32
|
-
#pserver.disconnect
|
1
|
+
#########################################################################
|
2
|
+
# example_server.rb
|
3
|
+
#
|
4
|
+
# A simple named pipe server. Start this up in its own terminal window.
|
5
|
+
# You may have to use the task manager to kill it if you don't connect
|
6
|
+
# with the test client program.
|
7
|
+
#
|
8
|
+
# You can start this server with the 'rake example_server' task. Modify
|
9
|
+
# this code as you see fit.
|
10
|
+
#########################################################################
|
11
|
+
require 'win32/pipe'
|
12
|
+
include Win32
|
13
|
+
|
14
|
+
Thread.new { loop { sleep 0.01 } } # Allow Ctrl-C
|
15
|
+
|
16
|
+
puts "VERSION: " + Pipe::VERSION
|
17
|
+
|
18
|
+
# Block form
|
19
|
+
Pipe::Server.new('foo') do |pipe|
|
20
|
+
pipe.connect
|
21
|
+
data = pipe.read
|
22
|
+
puts "Got [#{data}]"
|
23
|
+
pipe.write "Thanks for the data!"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Non-block form
|
27
|
+
#pserver = Pipe::Server.new('foo')
|
28
|
+
#pserver.connect # put server in wait connect
|
29
|
+
#data = pserver.read
|
30
|
+
#puts "Got [#{data}]"
|
31
|
+
#pserver.write("Thanks for the data!")
|
32
|
+
#pserver.disconnect
|
33
33
|
#pserver.close
|
@@ -1,100 +1,100 @@
|
|
1
|
-
#######################################################################
|
2
|
-
# example_server_async.rb
|
3
|
-
#
|
4
|
-
# A simple, asynchronous named pipe server. Start this up in its own
|
5
|
-
# terminal window. You can run this program via the
|
6
|
-
# 'rake example_async_server' task.
|
7
|
-
#######################################################################
|
8
|
-
require 'win32/pipe'
|
9
|
-
include Win32
|
10
|
-
|
11
|
-
puts "VERSION: " + Pipe::VERSION
|
12
|
-
|
13
|
-
Thread.new { loop { sleep 0.01 } } # Allow Ctrl-C
|
14
|
-
|
15
|
-
CONNECTING_STATE = 0
|
16
|
-
READING_STATE = 1
|
17
|
-
WRITING_STATE = 2
|
18
|
-
|
19
|
-
class MyPipe < Pipe::Server
|
20
|
-
def connected
|
21
|
-
puts "connected"
|
22
|
-
@state = READING_STATE
|
23
|
-
end
|
24
|
-
|
25
|
-
def read_complete
|
26
|
-
puts "read_complete"
|
27
|
-
puts "Got [#{buffer}]"
|
28
|
-
@state = WRITING_STATE
|
29
|
-
end
|
30
|
-
|
31
|
-
def write_complete
|
32
|
-
puts "write_complete"
|
33
|
-
disconnect
|
34
|
-
@state = CONNECTING_STATE
|
35
|
-
end
|
36
|
-
|
37
|
-
def reconnect
|
38
|
-
disconnect
|
39
|
-
mainloop
|
40
|
-
end
|
41
|
-
|
42
|
-
def mainloop
|
43
|
-
@state = CONNECTING_STATE
|
44
|
-
while true
|
45
|
-
if wait(1) # wait for 1 second
|
46
|
-
if pending? # IO is pending
|
47
|
-
case @state
|
48
|
-
when CONNECTING_STATE
|
49
|
-
connected
|
50
|
-
when READING_STATE
|
51
|
-
if transferred == 0
|
52
|
-
reconnect
|
53
|
-
break
|
54
|
-
end
|
55
|
-
read_complete
|
56
|
-
when WRITING_STATE
|
57
|
-
if transferred != length
|
58
|
-
reconnect
|
59
|
-
break
|
60
|
-
end
|
61
|
-
write_complete
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
case @state
|
66
|
-
when CONNECTING_STATE
|
67
|
-
if connect
|
68
|
-
connected
|
69
|
-
end
|
70
|
-
when READING_STATE
|
71
|
-
if read
|
72
|
-
if !pending?
|
73
|
-
read_complete
|
74
|
-
end
|
75
|
-
else
|
76
|
-
reconnect
|
77
|
-
end
|
78
|
-
when WRITING_STATE
|
79
|
-
if write("Thanks for the data!")
|
80
|
-
if not pending?
|
81
|
-
write_complete
|
82
|
-
end
|
83
|
-
else
|
84
|
-
reconnect
|
85
|
-
break
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
sleep(1)
|
91
|
-
puts "pipe server is running"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
flags = Pipe::ACCESS_DUPLEX | Pipe::OVERLAPPED
|
97
|
-
|
98
|
-
MyPipe.new('foo', 0, flags) do |pipe|
|
99
|
-
pipe.mainloop
|
100
|
-
end
|
1
|
+
#######################################################################
|
2
|
+
# example_server_async.rb
|
3
|
+
#
|
4
|
+
# A simple, asynchronous named pipe server. Start this up in its own
|
5
|
+
# terminal window. You can run this program via the
|
6
|
+
# 'rake example_async_server' task.
|
7
|
+
#######################################################################
|
8
|
+
require 'win32/pipe'
|
9
|
+
include Win32
|
10
|
+
|
11
|
+
puts "VERSION: " + Pipe::VERSION
|
12
|
+
|
13
|
+
Thread.new { loop { sleep 0.01 } } # Allow Ctrl-C
|
14
|
+
|
15
|
+
CONNECTING_STATE = 0
|
16
|
+
READING_STATE = 1
|
17
|
+
WRITING_STATE = 2
|
18
|
+
|
19
|
+
class MyPipe < Pipe::Server
|
20
|
+
def connected
|
21
|
+
puts "connected"
|
22
|
+
@state = READING_STATE
|
23
|
+
end
|
24
|
+
|
25
|
+
def read_complete
|
26
|
+
puts "read_complete"
|
27
|
+
puts "Got [#{buffer}]"
|
28
|
+
@state = WRITING_STATE
|
29
|
+
end
|
30
|
+
|
31
|
+
def write_complete
|
32
|
+
puts "write_complete"
|
33
|
+
disconnect
|
34
|
+
@state = CONNECTING_STATE
|
35
|
+
end
|
36
|
+
|
37
|
+
def reconnect
|
38
|
+
disconnect
|
39
|
+
mainloop
|
40
|
+
end
|
41
|
+
|
42
|
+
def mainloop
|
43
|
+
@state = CONNECTING_STATE
|
44
|
+
while true
|
45
|
+
if wait(1) # wait for 1 second
|
46
|
+
if pending? # IO is pending
|
47
|
+
case @state
|
48
|
+
when CONNECTING_STATE
|
49
|
+
connected
|
50
|
+
when READING_STATE
|
51
|
+
if transferred == 0
|
52
|
+
reconnect
|
53
|
+
break
|
54
|
+
end
|
55
|
+
read_complete
|
56
|
+
when WRITING_STATE
|
57
|
+
if transferred != length
|
58
|
+
reconnect
|
59
|
+
break
|
60
|
+
end
|
61
|
+
write_complete
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
case @state
|
66
|
+
when CONNECTING_STATE
|
67
|
+
if connect
|
68
|
+
connected
|
69
|
+
end
|
70
|
+
when READING_STATE
|
71
|
+
if read
|
72
|
+
if !pending?
|
73
|
+
read_complete
|
74
|
+
end
|
75
|
+
else
|
76
|
+
reconnect
|
77
|
+
end
|
78
|
+
when WRITING_STATE
|
79
|
+
if write("Thanks for the data!")
|
80
|
+
if not pending?
|
81
|
+
write_complete
|
82
|
+
end
|
83
|
+
else
|
84
|
+
reconnect
|
85
|
+
break
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
sleep(1)
|
91
|
+
puts "pipe server is running"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
flags = Pipe::ACCESS_DUPLEX | Pipe::OVERLAPPED
|
97
|
+
|
98
|
+
MyPipe.new('foo', 0, flags) do |pipe|
|
99
|
+
pipe.mainloop
|
100
|
+
end
|
data/lib/win32/pipe.rb
CHANGED
@@ -1,254 +1,251 @@
|
|
1
|
-
require '
|
2
|
-
require 'windows
|
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
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
require 'win32/pipe/server'
|
254
|
-
require 'win32/pipe/client'
|
1
|
+
require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'constants')
|
2
|
+
require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'functions')
|
3
|
+
|
4
|
+
# The Win32 module serves as a namespace only.
|
5
|
+
module Win32
|
6
|
+
# The Pipe class is an abstract base class for the Pipe::Server and
|
7
|
+
# Pipe::Client classes. Do not use this directly.
|
8
|
+
#
|
9
|
+
class Pipe
|
10
|
+
include Windows::Constants
|
11
|
+
include Windows::Functions
|
12
|
+
|
13
|
+
# Error raised when anything other than a SystemCallError occurs.
|
14
|
+
class Error < StandardError; end
|
15
|
+
|
16
|
+
# The version of this library
|
17
|
+
VERSION = '0.3.0'
|
18
|
+
|
19
|
+
PIPE_BUFFER_SIZE = 512 #:nodoc:
|
20
|
+
PIPE_TIMEOUT = 5000 #:nodoc:
|
21
|
+
|
22
|
+
# Blocking mode is enabled
|
23
|
+
WAIT = PIPE_WAIT
|
24
|
+
|
25
|
+
# Nonblocking mode is enabled
|
26
|
+
NOWAIT = PIPE_NOWAIT
|
27
|
+
|
28
|
+
# The pipe is bi-directional. Both server and client processes can read
|
29
|
+
# from and write to the pipe.
|
30
|
+
ACCESS_DUPLEX = PIPE_ACCESS_DUPLEX
|
31
|
+
|
32
|
+
# The flow of data in the pipe goes from client to server only.
|
33
|
+
ACCESS_INBOUND = PIPE_ACCESS_INBOUND
|
34
|
+
|
35
|
+
# The flow of data in the pipe goes from server to client only.
|
36
|
+
ACCESS_OUTBOUND = PIPE_ACCESS_OUTBOUND
|
37
|
+
|
38
|
+
# Data is written to the pipe as a stream of bytes.
|
39
|
+
TYPE_BYTE = PIPE_TYPE_BYTE
|
40
|
+
|
41
|
+
# Data is written to the pipe as a stream of messages.
|
42
|
+
TYPE_MESSAGE = PIPE_TYPE_MESSAGE
|
43
|
+
|
44
|
+
# Data is read from the pipe as a stream of bytes.
|
45
|
+
READMODE_BYTE = PIPE_READMODE_BYTE
|
46
|
+
|
47
|
+
# Data is read from the pipe as a stream of messages.
|
48
|
+
READMODE_MESSAGE = PIPE_READMODE_MESSAGE
|
49
|
+
|
50
|
+
# All instances beyond the first will fail with access denied errors.
|
51
|
+
FIRST_PIPE_INSTANCE = FILE_FLAG_FIRST_PIPE_INSTANCE
|
52
|
+
|
53
|
+
# Functions do not return until the data is written across the network.
|
54
|
+
WRITE_THROUGH = FILE_FLAG_WRITE_THROUGH
|
55
|
+
|
56
|
+
# Overlapped mode enables asynchronous communication.
|
57
|
+
OVERLAPPED = FILE_FLAG_OVERLAPPED
|
58
|
+
|
59
|
+
# The default pipe mode
|
60
|
+
DEFAULT_PIPE_MODE = NOWAIT
|
61
|
+
|
62
|
+
# The default open mode
|
63
|
+
DEFAULT_OPEN_MODE = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH
|
64
|
+
|
65
|
+
# The data still in the pipe's buffer
|
66
|
+
attr_reader :buffer
|
67
|
+
|
68
|
+
# The number of bytes to be written to the pipe.
|
69
|
+
attr_reader :size
|
70
|
+
|
71
|
+
# The number of characters that are actually transferred over the pipe.
|
72
|
+
attr_reader :transferred
|
73
|
+
|
74
|
+
# The full name of the pipe, e.g. "\\\\.\\pipe\\my_pipe"
|
75
|
+
attr_reader :name
|
76
|
+
|
77
|
+
# The pipe mode of the pipe.
|
78
|
+
attr_reader :open_mode
|
79
|
+
|
80
|
+
# The open mode of the pipe.
|
81
|
+
attr_reader :pipe_mode
|
82
|
+
|
83
|
+
# Abstract initializer for base class. This handles automatic prepending
|
84
|
+
# of '\\.\pipe\' to each named pipe so that you don't have to. Don't
|
85
|
+
# use this directly. Add the full implementation in subclasses.
|
86
|
+
#
|
87
|
+
# The default pipe mode is PIPE_WAIT.
|
88
|
+
#
|
89
|
+
# The default open mode is FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH.
|
90
|
+
#
|
91
|
+
def initialize(name, pipe_mode = DEFAULT_PIPE_MODE, open_mode = DEFAULT_OPEN_MODE)
|
92
|
+
@name = "\\\\.\\pipe\\" + name
|
93
|
+
|
94
|
+
@pipe_mode = pipe_mode.nil? ? DEFAULT_PIPE_MODE : pipe_mode
|
95
|
+
@open_mode = open_mode.nil? ? DEFAULT_OPEN_MODE : open_mode
|
96
|
+
|
97
|
+
@pipe = nil
|
98
|
+
@pending_io = false
|
99
|
+
@buffer = 0.chr * PIPE_BUFFER_SIZE
|
100
|
+
@size = 0
|
101
|
+
@overlapped = 0.chr * 20 # sizeof(OVERLAPPED)
|
102
|
+
@transferred = 0
|
103
|
+
@asynchronous = false
|
104
|
+
|
105
|
+
if open_mode & FILE_FLAG_OVERLAPPED > 0
|
106
|
+
@asynchronous = true
|
107
|
+
end
|
108
|
+
|
109
|
+
if @asynchronous
|
110
|
+
@event = CreateEvent(nil, true, true, nil)
|
111
|
+
@overlapped[16, 4] = [@event].pack('L')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Disconnects the pipe.
|
116
|
+
def disconnect
|
117
|
+
DisconnectNamedPipe(@pipe) if @pipe
|
118
|
+
end
|
119
|
+
|
120
|
+
# Closes the pipe.
|
121
|
+
#
|
122
|
+
def close
|
123
|
+
CloseHandle(@pipe) if @pipe
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns whether or not there is a pending IO operation on the pipe.
|
127
|
+
#
|
128
|
+
def pending?
|
129
|
+
@pending_io
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns whether or not the pipe is asynchronous.
|
133
|
+
#
|
134
|
+
def asynchronous?
|
135
|
+
@asynchronous
|
136
|
+
end
|
137
|
+
|
138
|
+
# Reads data from the pipe. You can read data from either end of a named
|
139
|
+
# pipe.
|
140
|
+
#
|
141
|
+
def read
|
142
|
+
bytes = FFI::MemoryPointer.new(:ulong)
|
143
|
+
@buffer = 0.chr * PIPE_BUFFER_SIZE
|
144
|
+
|
145
|
+
raise Error, "no pipe created" unless @pipe
|
146
|
+
|
147
|
+
if @asynchronous
|
148
|
+
bool = ReadFile(@pipe, @buffer, @buffer.size, bytes, @overlapped)
|
149
|
+
error = GetLastError()
|
150
|
+
|
151
|
+
bytes_read = bytes.read_ulong
|
152
|
+
|
153
|
+
if bool && bytes_read > 0
|
154
|
+
@pending_io = false
|
155
|
+
@buffer = @buffer[0, bytes_read]
|
156
|
+
return true
|
157
|
+
end
|
158
|
+
|
159
|
+
if !bool && error == ERROR_IO_PENDING
|
160
|
+
@pending_io = true
|
161
|
+
return true
|
162
|
+
end
|
163
|
+
|
164
|
+
return false
|
165
|
+
else
|
166
|
+
unless ReadFile(@pipe, @buffer, @buffer.size, bytes, nil)
|
167
|
+
raise SystemCallError.new("ReadFile", FFI.errno)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
@buffer.unpack("A*")
|
172
|
+
end
|
173
|
+
|
174
|
+
# Writes 'data' to the pipe. You can write data to either end of a
|
175
|
+
# named pipe.
|
176
|
+
#
|
177
|
+
def write(data)
|
178
|
+
@buffer = data
|
179
|
+
@size = data.size
|
180
|
+
bytes = FFI::MemoryPointer.new(:ulong)
|
181
|
+
|
182
|
+
raise Error, "no pipe created" unless @pipe
|
183
|
+
|
184
|
+
if @asynchronous
|
185
|
+
bool = WriteFile(@pipe, @buffer, @buffer.size, bytes, @overlapped)
|
186
|
+
error = GetLastError()
|
187
|
+
|
188
|
+
bytes_written = bytes.read_ulong
|
189
|
+
|
190
|
+
if bool && bytes_written > 0
|
191
|
+
@pending_io = false
|
192
|
+
return true
|
193
|
+
end
|
194
|
+
|
195
|
+
if !bool && error == ERROR_IO_PENDING
|
196
|
+
@pending_io = true
|
197
|
+
return true
|
198
|
+
end
|
199
|
+
|
200
|
+
return false
|
201
|
+
else
|
202
|
+
unless WriteFile(@pipe, @buffer, @buffer.size, bytes, nil)
|
203
|
+
raise SystemCallError.new("WriteFile", FFI.errno)
|
204
|
+
end
|
205
|
+
|
206
|
+
return true
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Returns the pipe object if an event (such as a client connection)
|
211
|
+
# occurs within the +max_time+ specified (in seconds). Otherwise, it
|
212
|
+
# returns false.
|
213
|
+
#
|
214
|
+
def wait(max_time = nil)
|
215
|
+
unless @asynchronous
|
216
|
+
raise Error, 'cannot wait in synchronous (blocking) mode'
|
217
|
+
end
|
218
|
+
|
219
|
+
max_time = max_time ? max_time * 1000 : INFINITE
|
220
|
+
|
221
|
+
wait = WaitForSingleObject(@event, max_time)
|
222
|
+
|
223
|
+
if wait == WAIT_TIMEOUT
|
224
|
+
return false
|
225
|
+
else
|
226
|
+
if wait != WAIT_OBJECT_0
|
227
|
+
raise SystemCallError.new("WaitForSingleObject", FFI.errno)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
if @pending_io
|
232
|
+
transferred = FFI::MemoryPointer.new(:ulong)
|
233
|
+
bool = GetOverlappedResult(@pipe, @overlapped, transferred, false)
|
234
|
+
|
235
|
+
unless bool
|
236
|
+
raise SystemCallError.new("GetOverlappedResult", FFI.errno)
|
237
|
+
end
|
238
|
+
|
239
|
+
@transferred = transferred.read_ulong
|
240
|
+
@buffer = @buffer[0, @transferred]
|
241
|
+
end
|
242
|
+
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
alias length size
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
require File.join(File.dirname(__FILE__), 'pipe', 'server')
|
251
|
+
require File.join(File.dirname(__FILE__), 'pipe', 'client')
|