nng-ruby 0.1.1 → 1.0.1

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/lib/nng/ffi.rb CHANGED
@@ -1,376 +1,508 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ffi'
4
-
5
- module NNG
6
- # FFI bindings for libnng
7
- module FFI
8
- extend ::FFI::Library
9
-
10
- # Try to load libnng from various locations
11
- @lib_paths = [
12
- File.expand_path('../../ext/nng/libnng.so.1.8.0', __dir__),
13
- '/usr/local/lib/libnng.so',
14
- '/usr/lib/libnng.so',
15
- '/usr/lib/x86_64-linux-gnu/libnng.so'
16
- ]
17
-
18
- @loaded_lib_path = nil
19
- @lib_paths.each do |path|
20
- if File.exist?(path)
21
- begin
22
- ffi_lib path
23
- @loaded_lib_path = path
24
- break
25
- rescue LoadError
26
- next
27
- end
28
- end
29
- end
30
-
31
- raise LoadError, "Could not find libnng.so in any of: #{@lib_paths.join(', ')}" unless @loaded_lib_path
32
-
33
- def self.loaded_lib_path
34
- @loaded_lib_path
35
- end
36
-
37
- # ============================================================================
38
- # Constants
39
- # ============================================================================
40
-
41
- NNG_MAJOR_VERSION = 1
42
- NNG_MINOR_VERSION = 8
43
- NNG_PATCH_VERSION = 0
44
-
45
- # Maximum address length
46
- NNG_MAXADDRLEN = 128
47
-
48
- # Error codes
49
- NNG_OK = 0
50
- NNG_EINTR = 1
51
- NNG_ENOMEM = 2
52
- NNG_EINVAL = 3
53
- NNG_EBUSY = 4
54
- NNG_ETIMEDOUT = 5
55
- NNG_ECONNREFUSED = 6
56
- NNG_ECLOSED = 7
57
- NNG_EAGAIN = 8
58
- NNG_ENOTSUP = 9
59
- NNG_EADDRINUSE = 10
60
- NNG_ESTATE = 11
61
- NNG_ENOENT = 12
62
- NNG_EPROTO = 13
63
- NNG_EUNREACHABLE = 14
64
- NNG_EADDRINVAL = 15
65
- NNG_EPERM = 16
66
- NNG_EMSGSIZE = 17
67
- NNG_ECONNABORTED = 18
68
- NNG_ECONNRESET = 19
69
- NNG_ECANCELED = 20
70
- NNG_ENOFILES = 21
71
- NNG_ENOSPC = 22
72
- NNG_EEXIST = 23
73
- NNG_EREADONLY = 24
74
- NNG_EWRITEONLY = 25
75
- NNG_ECRYPTO = 26
76
- NNG_EPEERAUTH = 27
77
- NNG_ENOARG = 28
78
- NNG_EAMBIGUOUS = 29
79
- NNG_EBADTYPE = 30
80
- NNG_ECONNSHUT = 31
81
- NNG_EINTERNAL = 1000
82
-
83
- # Flags
84
- NNG_FLAG_ALLOC = 1 # Allocate receive buffer
85
- NNG_FLAG_NONBLOCK = 2 # Non-blocking mode
86
-
87
- # Socket address families
88
- NNG_AF_UNSPEC = 0
89
- NNG_AF_INPROC = 1
90
- NNG_AF_IPC = 2
91
- NNG_AF_INET = 3
92
- NNG_AF_INET6 = 4
93
- NNG_AF_ZT = 5
94
- NNG_AF_ABSTRACT = 6
95
-
96
- # Pipe events
97
- NNG_PIPE_EV_ADD_PRE = 0
98
- NNG_PIPE_EV_ADD_POST = 1
99
- NNG_PIPE_EV_REM_POST = 2
100
- NNG_PIPE_EV_NUM = 3
101
-
102
- # ============================================================================
103
- # Type definitions
104
- # ============================================================================
105
-
106
- # nng_socket structure
107
- class NngSocket < ::FFI::Struct
108
- layout :id, :uint32
109
- end
110
-
111
- # nng_dialer structure
112
- class NngDialer < ::FFI::Struct
113
- layout :id, :uint32
114
- end
115
-
116
- # nng_listener structure
117
- class NngListener < ::FFI::Struct
118
- layout :id, :uint32
119
- end
120
-
121
- # nng_ctx structure
122
- class NngCtx < ::FFI::Struct
123
- layout :id, :uint32
124
- end
125
-
126
- # nng_pipe structure
127
- class NngPipe < ::FFI::Struct
128
- layout :id, :uint32
129
- end
130
-
131
- # nng_duration - time interval in milliseconds
132
- typedef :int32, :nng_duration
133
-
134
- # nng_time - absolute time in milliseconds
135
- typedef :uint64, :nng_time
136
-
137
- # Opaque types
138
- typedef :pointer, :nng_msg
139
- typedef :pointer, :nng_aio
140
- typedef :pointer, :nng_stat
141
-
142
- # Socket address structures
143
- class NngSockaddrInproc < ::FFI::Struct
144
- layout :sa_family, :uint16,
145
- :sa_name, [:char, NNG_MAXADDRLEN]
146
- end
147
-
148
- class NngSockaddrPath < ::FFI::Struct
149
- layout :sa_family, :uint16,
150
- :sa_path, [:char, NNG_MAXADDRLEN]
151
- end
152
-
153
- class NngSockaddrIn < ::FFI::Struct
154
- layout :sa_family, :uint16,
155
- :sa_port, :uint16,
156
- :sa_addr, :uint32
157
- end
158
-
159
- class NngSockaddrIn6 < ::FFI::Struct
160
- layout :sa_family, :uint16,
161
- :sa_port, :uint16,
162
- :sa_addr, [:uint8, 16],
163
- :sa_scope, :uint32
164
- end
165
-
166
- class NngSockaddrStorage < ::FFI::Struct
167
- layout :sa_family, :uint16,
168
- :sa_pad, [:uint64, 16]
169
- end
170
-
171
- class NngSockaddr < ::FFI::Union
172
- layout :s_family, :uint16,
173
- :s_inproc, NngSockaddrInproc,
174
- :s_ipc, NngSockaddrPath,
175
- :s_in, NngSockaddrIn,
176
- :s_in6, NngSockaddrIn6,
177
- :s_storage, NngSockaddrStorage
178
- end
179
-
180
- # ============================================================================
181
- # Core functions
182
- # ============================================================================
183
-
184
- # Library finalization
185
- attach_function :nng_fini, [], :void
186
-
187
- # Error handling
188
- attach_function :nng_strerror, [:int], :string
189
-
190
- # Socket functions
191
- attach_function :nng_close, [NngSocket.by_value], :int
192
- attach_function :nng_socket_id, [NngSocket.by_value], :int
193
-
194
- # Socket options - set
195
- attach_function :nng_setopt, [NngSocket.by_value, :string, :pointer, :size_t], :int
196
- attach_function :nng_setopt_bool, [NngSocket.by_value, :string, :bool], :int
197
- attach_function :nng_setopt_int, [NngSocket.by_value, :string, :int], :int
198
- attach_function :nng_setopt_size, [NngSocket.by_value, :string, :size_t], :int
199
- attach_function :nng_setopt_uint64, [NngSocket.by_value, :string, :uint64], :int
200
- attach_function :nng_setopt_string, [NngSocket.by_value, :string, :string], :int
201
- attach_function :nng_setopt_ptr, [NngSocket.by_value, :string, :pointer], :int
202
- attach_function :nng_setopt_ms, [NngSocket.by_value, :string, :nng_duration], :int
203
-
204
- # Socket options - get
205
- attach_function :nng_getopt, [NngSocket.by_value, :string, :pointer, :pointer], :int
206
- attach_function :nng_getopt_bool, [NngSocket.by_value, :string, :pointer], :int
207
- attach_function :nng_getopt_int, [NngSocket.by_value, :string, :pointer], :int
208
- attach_function :nng_getopt_size, [NngSocket.by_value, :string, :pointer], :int
209
- attach_function :nng_getopt_uint64, [NngSocket.by_value, :string, :pointer], :int
210
- attach_function :nng_getopt_string, [NngSocket.by_value, :string, :pointer], :int
211
- attach_function :nng_getopt_ptr, [NngSocket.by_value, :string, :pointer], :int
212
- attach_function :nng_getopt_ms, [NngSocket.by_value, :string, :pointer], :int
213
-
214
- # Connection management
215
- attach_function :nng_listen, [NngSocket.by_value, :string, :pointer, :int], :int
216
- attach_function :nng_dial, [NngSocket.by_value, :string, :pointer, :int], :int
217
-
218
- # Dialer functions
219
- attach_function :nng_dialer_create, [:pointer, NngSocket.by_value, :string], :int
220
- attach_function :nng_dialer_start, [NngDialer.by_value, :int], :int
221
- attach_function :nng_dialer_close, [NngDialer.by_value], :int
222
- attach_function :nng_dialer_id, [NngDialer.by_value], :int
223
-
224
- # Listener functions
225
- attach_function :nng_listener_create, [:pointer, NngSocket.by_value, :string], :int
226
- attach_function :nng_listener_start, [NngListener.by_value, :int], :int
227
- attach_function :nng_listener_close, [NngListener.by_value], :int
228
- attach_function :nng_listener_id, [NngListener.by_value], :int
229
-
230
- # Send and receive (synchronous)
231
- attach_function :nng_send, [NngSocket.by_value, :pointer, :size_t, :int], :int
232
- attach_function :nng_recv, [NngSocket.by_value, :pointer, :pointer, :int], :int
233
-
234
- # Message-based send/receive
235
- attach_function :nng_sendmsg, [NngSocket.by_value, :nng_msg, :int], :int
236
- attach_function :nng_recvmsg, [NngSocket.by_value, :pointer, :int], :int
237
-
238
- # Memory management
239
- attach_function :nng_free, [:pointer, :size_t], :void
240
- attach_function :nng_strfree, [:pointer], :void
241
-
242
- # Message functions
243
- attach_function :nng_msg_alloc, [:pointer, :size_t], :int
244
- attach_function :nng_msg_free, [:nng_msg], :void
245
- attach_function :nng_msg_realloc, [:nng_msg, :size_t], :int
246
- attach_function :nng_msg_header, [:nng_msg], :pointer
247
- attach_function :nng_msg_header_len, [:nng_msg], :size_t
248
- attach_function :nng_msg_body, [:nng_msg], :pointer
249
- attach_function :nng_msg_len, [:nng_msg], :size_t
250
- attach_function :nng_msg_append, [:nng_msg, :pointer, :size_t], :int
251
- attach_function :nng_msg_insert, [:nng_msg, :pointer, :size_t], :int
252
- attach_function :nng_msg_trim, [:nng_msg, :size_t], :int
253
- attach_function :nng_msg_chop, [:nng_msg, :size_t], :int
254
- attach_function :nng_msg_header_append, [:nng_msg, :pointer, :size_t], :int
255
- attach_function :nng_msg_header_insert, [:nng_msg, :pointer, :size_t], :int
256
- attach_function :nng_msg_header_trim, [:nng_msg, :size_t], :int
257
- attach_function :nng_msg_header_chop, [:nng_msg, :size_t], :int
258
- attach_function :nng_msg_clear, [:nng_msg], :void
259
- attach_function :nng_msg_header_clear, [:nng_msg], :void
260
- attach_function :nng_msg_dup, [:pointer, :nng_msg], :int
261
- attach_function :nng_msg_get_pipe, [:nng_msg], NngPipe.by_value
262
- attach_function :nng_msg_set_pipe, [:nng_msg, NngPipe.by_value], :void
263
-
264
- # Context functions
265
- attach_function :nng_ctx_open, [:pointer, NngSocket.by_value], :int
266
- attach_function :nng_ctx_close, [NngCtx.by_value], :int
267
- attach_function :nng_ctx_id, [NngCtx.by_value], :int
268
- attach_function :nng_ctx_send, [NngCtx.by_value, :nng_aio], :void
269
- attach_function :nng_ctx_recv, [NngCtx.by_value, :nng_aio], :void
270
- attach_function :nng_ctx_sendmsg, [NngCtx.by_value, :nng_msg, :int], :int
271
- attach_function :nng_ctx_recvmsg, [NngCtx.by_value, :pointer, :int], :int
272
-
273
- # Pipe functions
274
- attach_function :nng_pipe_id, [NngPipe.by_value], :int
275
- attach_function :nng_pipe_socket, [NngPipe.by_value], NngSocket.by_value
276
- attach_function :nng_pipe_dialer, [NngPipe.by_value], NngDialer.by_value
277
- attach_function :nng_pipe_listener, [NngPipe.by_value], NngListener.by_value
278
- attach_function :nng_pipe_close, [NngPipe.by_value], :int
279
-
280
- # Asynchronous I/O functions
281
- attach_function :nng_aio_alloc, [:pointer, :pointer, :pointer], :int
282
- attach_function :nng_aio_free, [:nng_aio], :void
283
- attach_function :nng_aio_stop, [:nng_aio], :void
284
- attach_function :nng_aio_result, [:nng_aio], :int
285
- attach_function :nng_aio_count, [:nng_aio], :size_t
286
- attach_function :nng_aio_cancel, [:nng_aio], :void
287
- attach_function :nng_aio_abort, [:nng_aio, :int], :void
288
- attach_function :nng_aio_wait, [:nng_aio], :void
289
- attach_function :nng_aio_set_msg, [:nng_aio, :nng_msg], :void
290
- attach_function :nng_aio_get_msg, [:nng_aio], :nng_msg
291
- attach_function :nng_aio_set_input, [:nng_aio, :uint, :pointer], :int
292
- attach_function :nng_aio_set_output, [:nng_aio, :uint, :pointer], :int
293
- attach_function :nng_aio_set_timeout, [:nng_aio, :nng_duration], :void
294
- attach_function :nng_aio_set_iov, [:nng_aio, :uint, :pointer], :int
295
- attach_function :nng_aio_begin, [:nng_aio], :bool
296
- attach_function :nng_aio_finish, [:nng_aio, :int], :void
297
- attach_function :nng_aio_defer, [:nng_aio, :pointer, :pointer], :void
298
-
299
- # Asynchronous send/receive
300
- attach_function :nng_send_aio, [NngSocket.by_value, :nng_aio], :void
301
- attach_function :nng_recv_aio, [NngSocket.by_value, :nng_aio], :void
302
-
303
- # Statistics functions
304
- attach_function :nng_stats_get, [:pointer], :int
305
- attach_function :nng_stats_free, [:nng_stat], :void
306
- attach_function :nng_stats_dump, [:nng_stat], :void
307
- attach_function :nng_stat_next, [:nng_stat], :nng_stat
308
- attach_function :nng_stat_child, [:nng_stat], :nng_stat
309
- attach_function :nng_stat_name, [:nng_stat], :string
310
- attach_function :nng_stat_type, [:nng_stat], :int
311
- attach_function :nng_stat_unit, [:nng_stat], :int
312
- attach_function :nng_stat_value, [:nng_stat], :uint64
313
- attach_function :nng_stat_desc, [:nng_stat], :string
314
-
315
- # Device functions (forwarder/reflector)
316
- attach_function :nng_device, [NngSocket.by_value, NngSocket.by_value], :int
317
-
318
- # Utility functions
319
- attach_function :nng_sleep_aio, [:nng_duration, :nng_aio], :void
320
- attach_function :nng_msleep, [:nng_duration], :void
321
-
322
- # URL parsing
323
- typedef :pointer, :nng_url
324
- attach_function :nng_url_parse, [:pointer, :string], :int
325
- attach_function :nng_url_free, [:nng_url], :void
326
- attach_function :nng_url_clone, [:pointer, :nng_url], :int
327
-
328
- # ============================================================================
329
- # Protocol-specific functions (will be attached when protocol is loaded)
330
- # ============================================================================
331
-
332
- # These will be attached by specific protocol modules:
333
- # - nng_pair0_open, nng_pair1_open
334
- # - nng_push0_open, nng_pull0_open
335
- # - nng_pub0_open, nng_sub0_open
336
- # - nng_req0_open, nng_rep0_open
337
- # - nng_surveyor0_open, nng_respondent0_open
338
- # - nng_bus0_open
339
-
340
- # ============================================================================
341
- # Helper methods
342
- # ============================================================================
343
-
344
- # Check error code and raise exception if not OK
345
- def self.check_error(ret, operation = "NNG operation")
346
- return if ret == NNG_OK
347
- error_msg = nng_strerror(ret)
348
- raise NNG::Error, "#{operation} failed: #{error_msg} (code: #{ret})"
349
- end
350
-
351
- # Create initialized socket
352
- def self.socket_initializer
353
- NngSocket.new.tap { |s| s[:id] = 0 }
354
- end
355
-
356
- # Create initialized dialer
357
- def self.dialer_initializer
358
- NngDialer.new.tap { |d| d[:id] = 0 }
359
- end
360
-
361
- # Create initialized listener
362
- def self.listener_initializer
363
- NngListener.new.tap { |l| l[:id] = 0 }
364
- end
365
-
366
- # Create initialized context
367
- def self.ctx_initializer
368
- NngCtx.new.tap { |c| c[:id] = 0 }
369
- end
370
-
371
- # Create initialized pipe
372
- def self.pipe_initializer
373
- NngPipe.new.tap { |p| p[:id] = 0 }
374
- end
375
- end
376
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+ require 'rbconfig'
5
+
6
+ module NNG
7
+ # FFI bindings for libnng
8
+ module FFI
9
+ extend ::FFI::Library
10
+
11
+ # Load install-time configuration if available
12
+ @install_config = {}
13
+ config_file = File.expand_path('../../ext/nng/nng_config.rb', __dir__)
14
+ if File.exist?(config_file)
15
+ require config_file
16
+ @install_config = NNG::InstallConfig::CONFIG rescue {}
17
+ end
18
+
19
+ # Detect platform and return library file patterns
20
+ def self.platform_info
21
+ case RbConfig::CONFIG['host_os']
22
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
23
+ { os: :windows, lib_pattern: 'nng*.dll', lib_name: 'nng.dll' }
24
+ when /darwin|mac os/
25
+ { os: :macos, lib_pattern: 'libnng*.dylib', lib_name: 'libnng.dylib' }
26
+ else
27
+ { os: :linux, lib_pattern: 'libnng.so*', lib_name: 'libnng.so' }
28
+ end
29
+ end
30
+
31
+ # Build library search paths with priority order:
32
+ # 1. ENV['NNG_LIB_PATH'] - Direct path to library file
33
+ # 2. ENV['NNG_LIB_DIR'] - Directory containing library
34
+ # 3. Install config (from gem install --with-nng-*)
35
+ # 4. Bundled library
36
+ # 5. System default paths
37
+ def self.build_lib_paths
38
+ paths = []
39
+ platform = platform_info
40
+
41
+ # Priority 1: Direct library path from environment
42
+ if ENV['NNG_LIB_PATH'] && !ENV['NNG_LIB_PATH'].empty?
43
+ paths << ENV['NNG_LIB_PATH']
44
+ puts "NNG: Using library from NNG_LIB_PATH: #{ENV['NNG_LIB_PATH']}" if ENV['NNG_DEBUG']
45
+ end
46
+
47
+ # Priority 2: Library directory from environment
48
+ if ENV['NNG_LIB_DIR'] && !ENV['NNG_LIB_DIR'].empty?
49
+ dir = ENV['NNG_LIB_DIR']
50
+ # Search for platform-specific library files in the directory
51
+ Dir.glob(File.join(dir, platform[:lib_pattern])).each { |lib| paths << lib }
52
+ puts "NNG: Searching in NNG_LIB_DIR: #{dir}" if ENV['NNG_DEBUG']
53
+ end
54
+
55
+ # Priority 3: Install-time configuration
56
+ if @install_config[:nng_lib]
57
+ paths << @install_config[:nng_lib]
58
+ puts "NNG: Using library from install config: #{@install_config[:nng_lib]}" if ENV['NNG_DEBUG']
59
+ elsif @install_config[:nng_dir]
60
+ nng_dir = @install_config[:nng_dir]
61
+ # Try common subdirectories based on platform
62
+ subdirs = case platform[:os]
63
+ when :windows
64
+ %w[bin lib]
65
+ when :macos
66
+ %w[lib]
67
+ else
68
+ %w[lib lib64 lib/x86_64-linux-gnu]
69
+ end
70
+
71
+ subdirs.each do |subdir|
72
+ lib_dir = File.join(nng_dir, subdir)
73
+ Dir.glob(File.join(lib_dir, platform[:lib_pattern])).each { |lib| paths << lib }
74
+ end
75
+ puts "NNG: Searching in install config dir: #{nng_dir}" if ENV['NNG_DEBUG']
76
+ end
77
+
78
+ # Priority 4: Bundled library (platform-specific)
79
+ bundled_libs = case platform[:os]
80
+ when :windows
81
+ [
82
+ File.expand_path('../../ext/nng/nng.dll', __dir__),
83
+ File.expand_path('../../ext/nng/libnng.dll', __dir__)
84
+ ]
85
+ when :macos
86
+ [
87
+ File.expand_path('../../ext/nng/libnng.1.11.0.dylib', __dir__),
88
+ File.expand_path('../../ext/nng/libnng.dylib', __dir__)
89
+ ]
90
+ else
91
+ [
92
+ File.expand_path('../../ext/nng/libnng.so.1.11.0', __dir__),
93
+ File.expand_path('../../ext/nng/libnng.so', __dir__)
94
+ ]
95
+ end
96
+ paths += bundled_libs
97
+
98
+ # Priority 5: System default paths (platform-specific)
99
+ case platform[:os]
100
+ when :windows
101
+ # Windows: check common DLL locations
102
+ paths += [
103
+ File.join(ENV['WINDIR'] || 'C:/Windows', 'System32/nng.dll'),
104
+ File.join(ENV['ProgramFiles'] || 'C:/Program Files', 'nng/bin/nng.dll')
105
+ ]
106
+ when :macos
107
+ # macOS: check common library locations
108
+ paths += [
109
+ '/usr/local/lib/libnng.dylib',
110
+ '/opt/homebrew/lib/libnng.dylib',
111
+ '/usr/lib/libnng.dylib'
112
+ ]
113
+ else
114
+ # Linux: check common library locations
115
+ paths += [
116
+ '/usr/local/lib/libnng.so',
117
+ '/usr/lib/libnng.so',
118
+ '/usr/lib/x86_64-linux-gnu/libnng.so',
119
+ '/usr/lib/aarch64-linux-gnu/libnng.so'
120
+ ]
121
+ end
122
+
123
+ paths.uniq
124
+ end
125
+
126
+ @lib_paths = build_lib_paths
127
+ @loaded_lib_path = nil
128
+
129
+ @lib_paths.each do |path|
130
+ if File.exist?(path)
131
+ begin
132
+ ffi_lib path
133
+ @loaded_lib_path = path
134
+ puts "NNG: Successfully loaded library from: #{path}" if ENV['NNG_DEBUG']
135
+ break
136
+ rescue LoadError => e
137
+ puts "NNG: Failed to load #{path}: #{e.message}" if ENV['NNG_DEBUG']
138
+ next
139
+ end
140
+ end
141
+ end
142
+
143
+ unless @loaded_lib_path
144
+ platform = platform_info
145
+ lib_name = platform[:lib_name]
146
+ error_msg = "Could not find NNG library (#{lib_name}) in any of the following locations:\n"
147
+ error_msg += @lib_paths.map { |p| " - #{p}" }.join("\n")
148
+ error_msg += "\n\nYou can specify a custom path using:\n"
149
+ error_msg += " - Environment variable: export NNG_LIB_PATH=/path/to/#{lib_name}\n"
150
+ error_msg += " - Environment variable: export NNG_LIB_DIR=/path/to/lib\n"
151
+ error_msg += " - Gem install option: gem install nng-ruby -- --with-nng-dir=/path/to/nng\n"
152
+ error_msg += " - Gem install option: gem install nng-ruby -- --with-nng-lib=/path/to/#{lib_name}"
153
+ raise LoadError, error_msg
154
+ end
155
+
156
+ def self.loaded_lib_path
157
+ @loaded_lib_path
158
+ end
159
+
160
+ def self.install_config
161
+ @install_config
162
+ end
163
+
164
+ # ============================================================================
165
+ # Constants
166
+ # ============================================================================
167
+
168
+ # NOTE: These are compile-time version constants for reference.
169
+ # Use nng_version() to get the actual runtime library version.
170
+ NNG_MAJOR_VERSION = 1
171
+ NNG_MINOR_VERSION = 8
172
+ NNG_PATCH_VERSION = 0
173
+
174
+ # Maximum address length
175
+ NNG_MAXADDRLEN = 128
176
+
177
+ # Error codes
178
+ NNG_OK = 0
179
+ NNG_EINTR = 1
180
+ NNG_ENOMEM = 2
181
+ NNG_EINVAL = 3
182
+ NNG_EBUSY = 4
183
+ NNG_ETIMEDOUT = 5
184
+ NNG_ECONNREFUSED = 6
185
+ NNG_ECLOSED = 7
186
+ NNG_EAGAIN = 8
187
+ NNG_ENOTSUP = 9
188
+ NNG_EADDRINUSE = 10
189
+ NNG_ESTATE = 11
190
+ NNG_ENOENT = 12
191
+ NNG_EPROTO = 13
192
+ NNG_EUNREACHABLE = 14
193
+ NNG_EADDRINVAL = 15
194
+ NNG_EPERM = 16
195
+ NNG_EMSGSIZE = 17
196
+ NNG_ECONNABORTED = 18
197
+ NNG_ECONNRESET = 19
198
+ NNG_ECANCELED = 20
199
+ NNG_ENOFILES = 21
200
+ NNG_ENOSPC = 22
201
+ NNG_EEXIST = 23
202
+ NNG_EREADONLY = 24
203
+ NNG_EWRITEONLY = 25
204
+ NNG_ECRYPTO = 26
205
+ NNG_EPEERAUTH = 27
206
+ NNG_ENOARG = 28
207
+ NNG_EAMBIGUOUS = 29
208
+ NNG_EBADTYPE = 30
209
+ NNG_ECONNSHUT = 31
210
+ NNG_EINTERNAL = 1000
211
+
212
+ # Flags
213
+ NNG_FLAG_ALLOC = 1 # Allocate receive buffer
214
+ NNG_FLAG_NONBLOCK = 2 # Non-blocking mode
215
+
216
+ # Socket address families
217
+ NNG_AF_UNSPEC = 0
218
+ NNG_AF_INPROC = 1
219
+ NNG_AF_IPC = 2
220
+ NNG_AF_INET = 3
221
+ NNG_AF_INET6 = 4
222
+ NNG_AF_ZT = 5
223
+ NNG_AF_ABSTRACT = 6
224
+
225
+ # Pipe events
226
+ NNG_PIPE_EV_ADD_PRE = 0
227
+ NNG_PIPE_EV_ADD_POST = 1
228
+ NNG_PIPE_EV_REM_POST = 2
229
+ NNG_PIPE_EV_NUM = 3
230
+
231
+ # ============================================================================
232
+ # Type definitions
233
+ # ============================================================================
234
+
235
+ # nng_socket structure
236
+ class NngSocket < ::FFI::Struct
237
+ layout :id, :uint32
238
+ end
239
+
240
+ # nng_dialer structure
241
+ class NngDialer < ::FFI::Struct
242
+ layout :id, :uint32
243
+ end
244
+
245
+ # nng_listener structure
246
+ class NngListener < ::FFI::Struct
247
+ layout :id, :uint32
248
+ end
249
+
250
+ # nng_ctx structure
251
+ class NngCtx < ::FFI::Struct
252
+ layout :id, :uint32
253
+ end
254
+
255
+ # nng_pipe structure
256
+ class NngPipe < ::FFI::Struct
257
+ layout :id, :uint32
258
+ end
259
+
260
+ # nng_duration - time interval in milliseconds
261
+ typedef :int32, :nng_duration
262
+
263
+ # nng_time - absolute time in milliseconds
264
+ typedef :uint64, :nng_time
265
+
266
+ # Opaque types
267
+ typedef :pointer, :nng_msg
268
+ typedef :pointer, :nng_aio
269
+ typedef :pointer, :nng_stat
270
+
271
+ # Socket address structures
272
+ class NngSockaddrInproc < ::FFI::Struct
273
+ layout :sa_family, :uint16,
274
+ :sa_name, [:char, NNG_MAXADDRLEN]
275
+ end
276
+
277
+ class NngSockaddrPath < ::FFI::Struct
278
+ layout :sa_family, :uint16,
279
+ :sa_path, [:char, NNG_MAXADDRLEN]
280
+ end
281
+
282
+ class NngSockaddrIn < ::FFI::Struct
283
+ layout :sa_family, :uint16,
284
+ :sa_port, :uint16,
285
+ :sa_addr, :uint32
286
+ end
287
+
288
+ class NngSockaddrIn6 < ::FFI::Struct
289
+ layout :sa_family, :uint16,
290
+ :sa_port, :uint16,
291
+ :sa_addr, [:uint8, 16],
292
+ :sa_scope, :uint32
293
+ end
294
+
295
+ class NngSockaddrStorage < ::FFI::Struct
296
+ layout :sa_family, :uint16,
297
+ :sa_pad, [:uint64, 16]
298
+ end
299
+
300
+ class NngSockaddr < ::FFI::Union
301
+ layout :s_family, :uint16,
302
+ :s_inproc, NngSockaddrInproc,
303
+ :s_ipc, NngSockaddrPath,
304
+ :s_in, NngSockaddrIn,
305
+ :s_in6, NngSockaddrIn6,
306
+ :s_storage, NngSockaddrStorage
307
+ end
308
+
309
+ # ============================================================================
310
+ # Core functions
311
+ # ============================================================================
312
+
313
+ # Library version
314
+ attach_function :nng_version, [], :string
315
+
316
+ # Library finalization
317
+ attach_function :nng_fini, [], :void
318
+
319
+ # Error handling
320
+ attach_function :nng_strerror, [:int], :string
321
+
322
+ # Socket functions
323
+ attach_function :nng_close, [NngSocket.by_value], :int
324
+ attach_function :nng_socket_id, [NngSocket.by_value], :int
325
+
326
+ # Socket options - set
327
+ attach_function :nng_setopt, [NngSocket.by_value, :string, :pointer, :size_t], :int
328
+ attach_function :nng_setopt_bool, [NngSocket.by_value, :string, :bool], :int
329
+ attach_function :nng_setopt_int, [NngSocket.by_value, :string, :int], :int
330
+ attach_function :nng_setopt_size, [NngSocket.by_value, :string, :size_t], :int
331
+ attach_function :nng_setopt_uint64, [NngSocket.by_value, :string, :uint64], :int
332
+ attach_function :nng_setopt_string, [NngSocket.by_value, :string, :string], :int
333
+ attach_function :nng_setopt_ptr, [NngSocket.by_value, :string, :pointer], :int
334
+ attach_function :nng_setopt_ms, [NngSocket.by_value, :string, :nng_duration], :int
335
+
336
+ # Socket options - get
337
+ attach_function :nng_getopt, [NngSocket.by_value, :string, :pointer, :pointer], :int
338
+ attach_function :nng_getopt_bool, [NngSocket.by_value, :string, :pointer], :int
339
+ attach_function :nng_getopt_int, [NngSocket.by_value, :string, :pointer], :int
340
+ attach_function :nng_getopt_size, [NngSocket.by_value, :string, :pointer], :int
341
+ attach_function :nng_getopt_uint64, [NngSocket.by_value, :string, :pointer], :int
342
+ attach_function :nng_getopt_string, [NngSocket.by_value, :string, :pointer], :int
343
+ attach_function :nng_getopt_ptr, [NngSocket.by_value, :string, :pointer], :int
344
+ attach_function :nng_getopt_ms, [NngSocket.by_value, :string, :pointer], :int
345
+
346
+ # Connection management
347
+ attach_function :nng_listen, [NngSocket.by_value, :string, :pointer, :int], :int
348
+ attach_function :nng_dial, [NngSocket.by_value, :string, :pointer, :int], :int
349
+
350
+ # Dialer functions
351
+ attach_function :nng_dialer_create, [:pointer, NngSocket.by_value, :string], :int
352
+ attach_function :nng_dialer_start, [NngDialer.by_value, :int], :int
353
+ attach_function :nng_dialer_close, [NngDialer.by_value], :int
354
+ attach_function :nng_dialer_id, [NngDialer.by_value], :int
355
+
356
+ # Listener functions
357
+ attach_function :nng_listener_create, [:pointer, NngSocket.by_value, :string], :int
358
+ attach_function :nng_listener_start, [NngListener.by_value, :int], :int
359
+ attach_function :nng_listener_close, [NngListener.by_value], :int
360
+ attach_function :nng_listener_id, [NngListener.by_value], :int
361
+
362
+ # Send and receive (synchronous)
363
+ attach_function :nng_send, [NngSocket.by_value, :pointer, :size_t, :int], :int
364
+ attach_function :nng_recv, [NngSocket.by_value, :pointer, :pointer, :int], :int
365
+
366
+ # Message-based send/receive
367
+ attach_function :nng_sendmsg, [NngSocket.by_value, :nng_msg, :int], :int
368
+ attach_function :nng_recvmsg, [NngSocket.by_value, :pointer, :int], :int
369
+
370
+ # Memory management
371
+ attach_function :nng_free, [:pointer, :size_t], :void
372
+ attach_function :nng_strfree, [:pointer], :void
373
+
374
+ # Message functions
375
+ attach_function :nng_msg_alloc, [:pointer, :size_t], :int
376
+ attach_function :nng_msg_free, [:nng_msg], :void
377
+ attach_function :nng_msg_realloc, [:nng_msg, :size_t], :int
378
+ attach_function :nng_msg_header, [:nng_msg], :pointer
379
+ attach_function :nng_msg_header_len, [:nng_msg], :size_t
380
+ attach_function :nng_msg_body, [:nng_msg], :pointer
381
+ attach_function :nng_msg_len, [:nng_msg], :size_t
382
+ attach_function :nng_msg_append, [:nng_msg, :pointer, :size_t], :int
383
+ attach_function :nng_msg_insert, [:nng_msg, :pointer, :size_t], :int
384
+ attach_function :nng_msg_trim, [:nng_msg, :size_t], :int
385
+ attach_function :nng_msg_chop, [:nng_msg, :size_t], :int
386
+ attach_function :nng_msg_header_append, [:nng_msg, :pointer, :size_t], :int
387
+ attach_function :nng_msg_header_insert, [:nng_msg, :pointer, :size_t], :int
388
+ attach_function :nng_msg_header_trim, [:nng_msg, :size_t], :int
389
+ attach_function :nng_msg_header_chop, [:nng_msg, :size_t], :int
390
+ attach_function :nng_msg_clear, [:nng_msg], :void
391
+ attach_function :nng_msg_header_clear, [:nng_msg], :void
392
+ attach_function :nng_msg_dup, [:pointer, :nng_msg], :int
393
+ attach_function :nng_msg_get_pipe, [:nng_msg], NngPipe.by_value
394
+ attach_function :nng_msg_set_pipe, [:nng_msg, NngPipe.by_value], :void
395
+
396
+ # Context functions
397
+ attach_function :nng_ctx_open, [:pointer, NngSocket.by_value], :int
398
+ attach_function :nng_ctx_close, [NngCtx.by_value], :int
399
+ attach_function :nng_ctx_id, [NngCtx.by_value], :int
400
+ attach_function :nng_ctx_send, [NngCtx.by_value, :nng_aio], :void
401
+ attach_function :nng_ctx_recv, [NngCtx.by_value, :nng_aio], :void
402
+ attach_function :nng_ctx_sendmsg, [NngCtx.by_value, :nng_msg, :int], :int
403
+ attach_function :nng_ctx_recvmsg, [NngCtx.by_value, :pointer, :int], :int
404
+
405
+ # Pipe functions
406
+ attach_function :nng_pipe_id, [NngPipe.by_value], :int
407
+ attach_function :nng_pipe_socket, [NngPipe.by_value], NngSocket.by_value
408
+ attach_function :nng_pipe_dialer, [NngPipe.by_value], NngDialer.by_value
409
+ attach_function :nng_pipe_listener, [NngPipe.by_value], NngListener.by_value
410
+ attach_function :nng_pipe_close, [NngPipe.by_value], :int
411
+
412
+ # Asynchronous I/O functions
413
+ attach_function :nng_aio_alloc, [:pointer, :pointer, :pointer], :int
414
+ attach_function :nng_aio_free, [:nng_aio], :void
415
+ attach_function :nng_aio_stop, [:nng_aio], :void
416
+ attach_function :nng_aio_result, [:nng_aio], :int
417
+ attach_function :nng_aio_count, [:nng_aio], :size_t
418
+ attach_function :nng_aio_cancel, [:nng_aio], :void
419
+ attach_function :nng_aio_abort, [:nng_aio, :int], :void
420
+ attach_function :nng_aio_wait, [:nng_aio], :void
421
+ attach_function :nng_aio_set_msg, [:nng_aio, :nng_msg], :void
422
+ attach_function :nng_aio_get_msg, [:nng_aio], :nng_msg
423
+ attach_function :nng_aio_set_input, [:nng_aio, :uint, :pointer], :int
424
+ attach_function :nng_aio_set_output, [:nng_aio, :uint, :pointer], :int
425
+ attach_function :nng_aio_set_timeout, [:nng_aio, :nng_duration], :void
426
+ attach_function :nng_aio_set_iov, [:nng_aio, :uint, :pointer], :int
427
+ attach_function :nng_aio_begin, [:nng_aio], :bool
428
+ attach_function :nng_aio_finish, [:nng_aio, :int], :void
429
+ attach_function :nng_aio_defer, [:nng_aio, :pointer, :pointer], :void
430
+
431
+ # Asynchronous send/receive
432
+ attach_function :nng_send_aio, [NngSocket.by_value, :nng_aio], :void
433
+ attach_function :nng_recv_aio, [NngSocket.by_value, :nng_aio], :void
434
+
435
+ # Statistics functions
436
+ attach_function :nng_stats_get, [:pointer], :int
437
+ attach_function :nng_stats_free, [:nng_stat], :void
438
+ attach_function :nng_stats_dump, [:nng_stat], :void
439
+ attach_function :nng_stat_next, [:nng_stat], :nng_stat
440
+ attach_function :nng_stat_child, [:nng_stat], :nng_stat
441
+ attach_function :nng_stat_name, [:nng_stat], :string
442
+ attach_function :nng_stat_type, [:nng_stat], :int
443
+ attach_function :nng_stat_unit, [:nng_stat], :int
444
+ attach_function :nng_stat_value, [:nng_stat], :uint64
445
+ attach_function :nng_stat_desc, [:nng_stat], :string
446
+
447
+ # Device functions (forwarder/reflector)
448
+ attach_function :nng_device, [NngSocket.by_value, NngSocket.by_value], :int
449
+
450
+ # Utility functions
451
+ attach_function :nng_sleep_aio, [:nng_duration, :nng_aio], :void
452
+ attach_function :nng_msleep, [:nng_duration], :void
453
+
454
+ # URL parsing
455
+ typedef :pointer, :nng_url
456
+ attach_function :nng_url_parse, [:pointer, :string], :int
457
+ attach_function :nng_url_free, [:nng_url], :void
458
+ attach_function :nng_url_clone, [:pointer, :nng_url], :int
459
+
460
+ # ============================================================================
461
+ # Protocol-specific functions (will be attached when protocol is loaded)
462
+ # ============================================================================
463
+
464
+ # These will be attached by specific protocol modules:
465
+ # - nng_pair0_open, nng_pair1_open
466
+ # - nng_push0_open, nng_pull0_open
467
+ # - nng_pub0_open, nng_sub0_open
468
+ # - nng_req0_open, nng_rep0_open
469
+ # - nng_surveyor0_open, nng_respondent0_open
470
+ # - nng_bus0_open
471
+
472
+ # ============================================================================
473
+ # Helper methods
474
+ # ============================================================================
475
+
476
+ # Check error code and raise exception if not OK
477
+ def self.check_error(ret, operation = "NNG operation")
478
+ return if ret == NNG_OK
479
+ error_msg = nng_strerror(ret)
480
+ raise NNG::Error, "#{operation} failed: #{error_msg} (code: #{ret})"
481
+ end
482
+
483
+ # Create initialized socket
484
+ def self.socket_initializer
485
+ NngSocket.new.tap { |s| s[:id] = 0 }
486
+ end
487
+
488
+ # Create initialized dialer
489
+ def self.dialer_initializer
490
+ NngDialer.new.tap { |d| d[:id] = 0 }
491
+ end
492
+
493
+ # Create initialized listener
494
+ def self.listener_initializer
495
+ NngListener.new.tap { |l| l[:id] = 0 }
496
+ end
497
+
498
+ # Create initialized context
499
+ def self.ctx_initializer
500
+ NngCtx.new.tap { |c| c[:id] = 0 }
501
+ end
502
+
503
+ # Create initialized pipe
504
+ def self.pipe_initializer
505
+ NngPipe.new.tap { |p| p[:id] = 0 }
506
+ end
507
+ end
508
+ end