win32-pipe 0.3.6 → 0.3.7

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.
@@ -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')