win32-pipe 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,251 +1,250 @@
1
- require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'constants')
2
- require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'functions')
3
- require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'structs')
4
-
5
- # The Win32 module serves as a namespace only.
6
- module Win32
7
- # The Pipe class is an abstract base class for the Pipe::Server and
8
- # Pipe::Client classes. Do not use this directly.
9
- #
10
- class Pipe
11
- include Windows::Constants
12
- include Windows::Functions
13
- include Windows::Structs
14
-
15
- # Error raised when anything other than a SystemCallError occurs.
16
- class Error < StandardError; end
17
-
18
- # The version of this library
19
- VERSION = '0.3.6'
20
-
21
- DEFAULT_PIPE_BUFFER_SIZE = 4096 #:nodoc:
22
- PIPE_TIMEOUT = 5000 #:nodoc:
23
-
24
- # Blocking mode is enabled
25
- WAIT = PIPE_WAIT
26
-
27
- # Nonblocking mode is enabled
28
- NOWAIT = PIPE_NOWAIT
29
-
30
- # The pipe is bi-directional. Both server and client processes can read
31
- # from and write to the pipe.
32
- ACCESS_DUPLEX = PIPE_ACCESS_DUPLEX
33
-
34
- # The flow of data in the pipe goes from client to server only.
35
- ACCESS_INBOUND = PIPE_ACCESS_INBOUND
36
-
37
- # The flow of data in the pipe goes from server to client only.
38
- ACCESS_OUTBOUND = PIPE_ACCESS_OUTBOUND
39
-
40
- # Data is written to the pipe as a stream of bytes.
41
- TYPE_BYTE = PIPE_TYPE_BYTE
42
-
43
- # Data is written to the pipe as a stream of messages.
44
- TYPE_MESSAGE = PIPE_TYPE_MESSAGE
45
-
46
- # Data is read from the pipe as a stream of bytes.
47
- READMODE_BYTE = PIPE_READMODE_BYTE
48
-
49
- # Data is read from the pipe as a stream of messages.
50
- READMODE_MESSAGE = PIPE_READMODE_MESSAGE
51
-
52
- # All instances beyond the first will fail with access denied errors.
53
- FIRST_PIPE_INSTANCE = FILE_FLAG_FIRST_PIPE_INSTANCE
54
-
55
- # Functions do not return until the data is written across the network.
56
- WRITE_THROUGH = FILE_FLAG_WRITE_THROUGH
57
-
58
- # Overlapped mode enables asynchronous communication.
59
- OVERLAPPED = FILE_FLAG_OVERLAPPED
60
-
61
- # The default pipe mode
62
- DEFAULT_PIPE_MODE = PIPE_WAIT
63
-
64
- # The default open mode
65
- DEFAULT_OPEN_MODE = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH
66
-
67
- # The data still in the pipe's buffer
68
- attr_reader :buffer
69
-
70
- # The number of bytes to be written to the pipe.
71
- attr_reader :size
72
-
73
- # The number of characters that are actually transferred over the pipe.
74
- attr_reader :transferred
75
-
76
- # The full name of the pipe, e.g. "\\\\.\\pipe\\my_pipe"
77
- attr_reader :name
78
-
79
- # The pipe mode of the pipe.
80
- attr_reader :open_mode
81
-
82
- # The open mode of the pipe.
83
- attr_reader :pipe_mode
84
-
85
- # Abstract initializer for base class. This handles automatic prepending
86
- # of '\\.\pipe\' to each named pipe so that you don't have to. Don't
87
- # use this directly. Add the full implementation in subclasses.
88
- #
89
- # The default pipe mode is PIPE_WAIT.
90
- #
91
- # The default open mode is FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH.
92
- #
93
- def initialize(name, pipe_mode = DEFAULT_PIPE_MODE, open_mode = DEFAULT_OPEN_MODE, pipe_buffer_size = DEFAULT_PIPE_BUFFER_SIZE)
94
- @name = "\\\\.\\pipe\\" + name
95
-
96
- @pipe_mode = pipe_mode.nil? ? DEFAULT_PIPE_MODE : pipe_mode
97
- @open_mode = open_mode.nil? ? DEFAULT_OPEN_MODE : open_mode
98
-
99
- @pipe = nil
100
- @pending_io = false
101
- @buffer = ''
102
- @ffi_buffer = FFI::Buffer.new( pipe_buffer_size )
103
- @size = 0
104
- @overlapped = nil
105
- @transferred = 0
106
- @asynchronous = false
107
- @pipe_buffer_size = pipe_buffer_size
108
-
109
- if open_mode & FILE_FLAG_OVERLAPPED > 0
110
- @asynchronous = true
111
- end
112
-
113
- if @asynchronous
114
- @event = CreateEvent(nil, true, true, nil)
115
- @overlapped = Overlapped.new
116
- @overlapped[:hEvent] = @event
117
- end
118
- end
119
-
120
- # Disconnects the pipe.
121
- def disconnect
122
- DisconnectNamedPipe(@pipe) if @pipe
123
- end
124
-
125
- # Closes the pipe.
126
- #
127
- def close
128
- CloseHandle(@pipe) if @pipe
129
- end
130
-
131
- # Returns whether or not there is a pending IO operation on the pipe.
132
- #
133
- def pending?
134
- @pending_io
135
- end
136
-
137
- # Returns whether or not the pipe is asynchronous.
138
- #
139
- def asynchronous?
140
- @asynchronous
141
- end
142
-
143
- # Reads data from the pipe. You can read data from either end of a named
144
- # pipe.
145
- #
146
- def read
147
- bytes = FFI::MemoryPointer.new(:ulong)
148
-
149
- raise Error, "no pipe created" unless @pipe
150
-
151
- if @asynchronous
152
- bool = ReadFile(@pipe, @ffi_buffer, @ffi_buffer.size, bytes, @overlapped)
153
- bytes_read = bytes.read_ulong
154
-
155
- if bool && bytes_read > 0
156
- @pending_io = false
157
- @buffer = @ffi_buffer.get_string(0, bytes_read)
158
- return true
159
- end
160
-
161
- error = GetLastError()
162
- if !bool && error == ERROR_IO_PENDING
163
- @pending_io = true
164
- return true
165
- end
166
-
167
- return false
168
- else
169
- unless ReadFile(@pipe, @ffi_buffer, @ffi_buffer.size, bytes, nil)
170
- raise SystemCallError.new("ReadFile", FFI.errno)
171
- end
172
- @buffer = @ffi_buffer.get_string(0, bytes.read_ulong)
173
- end
174
- end
175
-
176
- # Writes 'data' to the pipe. You can write data to either end of a
177
- # named pipe.
178
- #
179
- def write(data)
180
- @size = data.size
181
- bytes = FFI::MemoryPointer.new(:ulong)
182
-
183
- raise Error, "no pipe created" unless @pipe
184
-
185
- if @asynchronous
186
- bool = WriteFile(@pipe, @data, @data.size, bytes, @overlapped)
187
- bytes_written = bytes.read_ulong
188
-
189
- if bool && bytes_written > 0
190
- @pending_io = false
191
- return true
192
- end
193
-
194
- error = GetLastError()
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, data, data.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 = @ffi_buffer.get_string(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')
1
+ require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'constants')
2
+ require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'functions')
3
+ require File.join(File.dirname(__FILE__), 'pipe', 'windows', 'structs')
4
+
5
+ # The Win32 module serves as a namespace only.
6
+ module Win32
7
+ # The Pipe class is an abstract base class for the Pipe::Server and
8
+ # Pipe::Client classes. Do not use this directly.
9
+ #
10
+ class Pipe
11
+ include Windows::Constants
12
+ include Windows::Functions
13
+ include Windows::Structs
14
+
15
+ # Error raised when anything other than a SystemCallError occurs.
16
+ class Error < StandardError; end
17
+
18
+ # The version of this library
19
+ VERSION = '0.3.7'
20
+
21
+ DEFAULT_PIPE_BUFFER_SIZE = 4096 #:nodoc:
22
+ PIPE_TIMEOUT = 5000 #:nodoc:
23
+
24
+ # Blocking mode is enabled
25
+ WAIT = PIPE_WAIT
26
+
27
+ # Nonblocking mode is enabled
28
+ NOWAIT = PIPE_NOWAIT
29
+
30
+ # The pipe is bi-directional. Both server and client processes can read
31
+ # from and write to the pipe.
32
+ ACCESS_DUPLEX = PIPE_ACCESS_DUPLEX
33
+
34
+ # The flow of data in the pipe goes from client to server only.
35
+ ACCESS_INBOUND = PIPE_ACCESS_INBOUND
36
+
37
+ # The flow of data in the pipe goes from server to client only.
38
+ ACCESS_OUTBOUND = PIPE_ACCESS_OUTBOUND
39
+
40
+ # Data is written to the pipe as a stream of bytes.
41
+ TYPE_BYTE = PIPE_TYPE_BYTE
42
+
43
+ # Data is written to the pipe as a stream of messages.
44
+ TYPE_MESSAGE = PIPE_TYPE_MESSAGE
45
+
46
+ # Data is read from the pipe as a stream of bytes.
47
+ READMODE_BYTE = PIPE_READMODE_BYTE
48
+
49
+ # Data is read from the pipe as a stream of messages.
50
+ READMODE_MESSAGE = PIPE_READMODE_MESSAGE
51
+
52
+ # All instances beyond the first will fail with access denied errors.
53
+ FIRST_PIPE_INSTANCE = FILE_FLAG_FIRST_PIPE_INSTANCE
54
+
55
+ # Functions do not return until the data is written across the network.
56
+ WRITE_THROUGH = FILE_FLAG_WRITE_THROUGH
57
+
58
+ # Overlapped mode enables asynchronous communication.
59
+ OVERLAPPED = FILE_FLAG_OVERLAPPED
60
+
61
+ # The default pipe mode
62
+ DEFAULT_PIPE_MODE = PIPE_WAIT
63
+
64
+ # The default open mode
65
+ DEFAULT_OPEN_MODE = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH
66
+
67
+ # The data still in the pipe's buffer
68
+ attr_reader :buffer
69
+
70
+ # The number of bytes to be written to the pipe.
71
+ attr_reader :size
72
+
73
+ # The number of characters that are actually transferred over the pipe.
74
+ attr_reader :transferred
75
+
76
+ # The full name of the pipe, e.g. "\\\\.\\pipe\\my_pipe"
77
+ attr_reader :name
78
+
79
+ # The pipe mode of the pipe.
80
+ attr_reader :open_mode
81
+
82
+ # The open mode of the pipe.
83
+ attr_reader :pipe_mode
84
+
85
+ # Abstract initializer for base class. This handles automatic prepending
86
+ # of '\\.\pipe\' to each named pipe so that you don't have to. Don't
87
+ # use this directly. Add the full implementation in subclasses.
88
+ #
89
+ # The default pipe mode is PIPE_WAIT.
90
+ #
91
+ # The default open mode is FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH.
92
+ #
93
+ def initialize(name, pipe_mode = DEFAULT_PIPE_MODE, open_mode = DEFAULT_OPEN_MODE, pipe_buffer_size = DEFAULT_PIPE_BUFFER_SIZE)
94
+ @name = "\\\\.\\pipe\\" + name
95
+
96
+ @pipe_mode = pipe_mode.nil? ? DEFAULT_PIPE_MODE : pipe_mode
97
+ @open_mode = open_mode.nil? ? DEFAULT_OPEN_MODE : open_mode
98
+
99
+ @pipe = nil
100
+ @pending_io = false
101
+ @buffer = ''
102
+ @ffi_buffer = FFI::Buffer.new( pipe_buffer_size )
103
+ @size = 0
104
+ @overlapped = nil
105
+ @transferred = 0
106
+ @asynchronous = false
107
+ @pipe_buffer_size = pipe_buffer_size
108
+
109
+ if open_mode & FILE_FLAG_OVERLAPPED > 0
110
+ @asynchronous = true
111
+ end
112
+
113
+ if @asynchronous
114
+ @event = CreateEvent(nil, 1, 1, nil)
115
+ @overlapped = Overlapped.new
116
+ @overlapped[:hEvent] = @event
117
+ end
118
+ end
119
+
120
+ # Disconnects the pipe.
121
+ def disconnect
122
+ DisconnectNamedPipe(@pipe) if @pipe
123
+ end
124
+
125
+ # Closes the pipe.
126
+ #
127
+ def close
128
+ CloseHandle(@pipe) if @pipe
129
+ end
130
+
131
+ # Returns whether or not there is a pending IO operation on the pipe.
132
+ #
133
+ def pending?
134
+ @pending_io
135
+ end
136
+
137
+ # Returns whether or not the pipe is asynchronous.
138
+ #
139
+ def asynchronous?
140
+ @asynchronous
141
+ end
142
+
143
+ # Reads data from the pipe. You can read data from either end of a named
144
+ # pipe.
145
+ #
146
+ def read
147
+ bytes = FFI::MemoryPointer.new(:ulong)
148
+
149
+ raise Error, "no pipe created" unless @pipe
150
+
151
+ if @asynchronous
152
+ bool = ReadFile(@pipe, @ffi_buffer, @ffi_buffer.size, bytes, @overlapped)
153
+ bytes_read = bytes.read_ulong
154
+
155
+ if bool && bytes_read > 0
156
+ @pending_io = false
157
+ @buffer = @ffi_buffer.get_string(0, bytes_read)
158
+ return true
159
+ end
160
+
161
+ error = GetLastError()
162
+ if !bool && error == ERROR_IO_PENDING
163
+ @pending_io = true
164
+ return true
165
+ end
166
+
167
+ return false
168
+ else
169
+ unless ReadFile(@pipe, @ffi_buffer, @ffi_buffer.size, bytes, nil)
170
+ raise SystemCallError.new("ReadFile", FFI.errno)
171
+ end
172
+ @buffer = @ffi_buffer.get_string(0, bytes.read_ulong)
173
+ end
174
+ end
175
+
176
+ # Writes 'data' to the pipe. You can write data to either end of a
177
+ # named pipe.
178
+ #
179
+ def write(data)
180
+ bytes = FFI::MemoryPointer.new(:ulong)
181
+
182
+ raise Error, "no pipe created" unless @pipe
183
+
184
+ if @asynchronous
185
+ bool = WriteFile(@pipe, data, data.size, bytes, @overlapped)
186
+ bytes_written = bytes.read_ulong
187
+
188
+ if bool && bytes_written > 0
189
+ @pending_io = false
190
+ return true
191
+ end
192
+
193
+ error = GetLastError()
194
+ if !bool && error == ERROR_IO_PENDING
195
+ @pending_io = true
196
+ return true
197
+ end
198
+
199
+ return false
200
+ else
201
+ unless WriteFile(@pipe, data, data.size, bytes, nil)
202
+ raise SystemCallError.new("WriteFile", FFI.errno)
203
+ end
204
+
205
+ return true
206
+ end
207
+ end
208
+
209
+ # Returns the pipe object if an event (such as a client connection)
210
+ # occurs within the +max_time+ specified (in seconds). Otherwise, it
211
+ # returns false.
212
+ #
213
+ def wait(max_time = nil)
214
+ unless @asynchronous
215
+ raise Error, 'cannot wait in synchronous (blocking) mode'
216
+ end
217
+
218
+ max_time = max_time ? max_time * 1000 : INFINITE
219
+
220
+ wait = WaitForSingleObject(@event, max_time)
221
+
222
+ if wait == WAIT_TIMEOUT
223
+ return false
224
+ else
225
+ if wait != WAIT_OBJECT_0
226
+ raise SystemCallError.new("WaitForSingleObject", FFI.errno)
227
+ end
228
+ end
229
+
230
+ if @pending_io
231
+ transferred = FFI::MemoryPointer.new(:ulong)
232
+ bool = GetOverlappedResult(@pipe, @overlapped, transferred, 0)
233
+
234
+ unless bool
235
+ raise SystemCallError.new("GetOverlappedResult", FFI.errno)
236
+ end
237
+
238
+ @transferred = transferred.read_ulong
239
+ @buffer = @ffi_buffer.get_string(0, @transferred)
240
+ end
241
+
242
+ self
243
+ end
244
+
245
+ alias length size
246
+ end
247
+ end
248
+
249
+ require File.join(File.dirname(__FILE__), 'pipe', 'server')
250
+ require File.join(File.dirname(__FILE__), 'pipe', 'client')