log-courier 1.0.21.ga82ca4c
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.
- checksums.yaml +7 -0
- data/lib/log-courier/client.rb +352 -0
- data/lib/log-courier/client_tls.rb +217 -0
- data/lib/log-courier/event_queue.rb +194 -0
- data/lib/log-courier/server.rb +185 -0
- data/lib/log-courier/server_tcp.rb +275 -0
- data/lib/log-courier/server_zmq.rb +219 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 480d6e6a5958b6f307727dfa1713e8a9c0a10d29
|
4
|
+
data.tar.gz: 2f2de7aeedd2e539a16412dd40f8321ecc9cff20
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3d2d449239c58e05a7654ad0f77148b2fd8ac5ebf0094f50b85c7311cb904650cc426a55aa2918a9b9334c70c283ca1d7aa47cb47c94b0999011bfc0949270b7
|
7
|
+
data.tar.gz: 8e51f6507f0b12a7ed56a17fb28213ea9a7f71b5257544c8191ad19bb70e91f1c6a8e940d37203fab587f3c564deb0551426fc8996081a7101faaf707d014748
|
@@ -0,0 +1,352 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Copyright 2014 Jason Woods.
|
4
|
+
#
|
5
|
+
# This file is a modification of code from Logstash Forwarder.
|
6
|
+
# Copyright 2012-2013 Jordan Sissel and contributors.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
|
20
|
+
require 'log-courier/event_queue'
|
21
|
+
require 'multi_json'
|
22
|
+
require 'thread'
|
23
|
+
require 'zlib'
|
24
|
+
|
25
|
+
module LogCourier
|
26
|
+
# TODO: Make these shared
|
27
|
+
class ClientShutdownSignal < StandardError; end
|
28
|
+
class ClientProtocolError < StandardError; end
|
29
|
+
|
30
|
+
# Describes a pending payload
|
31
|
+
class PendingPayload
|
32
|
+
attr_accessor :ack_events
|
33
|
+
attr_accessor :events
|
34
|
+
attr_accessor :nonce
|
35
|
+
attr_accessor :data
|
36
|
+
|
37
|
+
attr_accessor :previous
|
38
|
+
attr_accessor :next
|
39
|
+
|
40
|
+
def initialize(options = {})
|
41
|
+
@ack_events = 0
|
42
|
+
|
43
|
+
options.each do |k, v|
|
44
|
+
raise ArgumentError unless self.respond_to?(k)
|
45
|
+
instance_variable_set "@#{k}", v
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Implementation of a single client connection
|
51
|
+
class Client
|
52
|
+
def initialize(options = {})
|
53
|
+
@options = {
|
54
|
+
logger: nil,
|
55
|
+
spool_size: 1024,
|
56
|
+
idle_timeout: 5
|
57
|
+
}.merge!(options)
|
58
|
+
|
59
|
+
@logger = @options[:logger]
|
60
|
+
|
61
|
+
require 'log-courier/client_tls'
|
62
|
+
@client = ClientTls.new(@options)
|
63
|
+
|
64
|
+
# Load the json adapter
|
65
|
+
@json_adapter = MultiJson.adapter.instance
|
66
|
+
|
67
|
+
@event_queue = EventQueue.new @options[:spool_size]
|
68
|
+
@pending_payloads = {}
|
69
|
+
@first_payload = nil
|
70
|
+
@last_payload = nil
|
71
|
+
|
72
|
+
# Start the spooler which will collect events into chunks
|
73
|
+
@send_ready = false
|
74
|
+
@send_mutex = Mutex.new
|
75
|
+
@send_cond = ConditionVariable.new
|
76
|
+
@spooler_thread = Thread.new do
|
77
|
+
run_spooler
|
78
|
+
end
|
79
|
+
|
80
|
+
@pending_ping = false
|
81
|
+
|
82
|
+
# Start the IO thread
|
83
|
+
@io_control = EventQueue.new 1
|
84
|
+
@io_thread = Thread.new do
|
85
|
+
run_io
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def publish(event)
|
90
|
+
# Pass the event into the spooler
|
91
|
+
@event_queue << event
|
92
|
+
end
|
93
|
+
|
94
|
+
def shutdown
|
95
|
+
# Raise a shutdown signal in the spooler and wait for it
|
96
|
+
@spooler_thread.raise ClientShutdownSignal
|
97
|
+
@io_thread.raise ClientShutdownSignal
|
98
|
+
@spooler_thread.join
|
99
|
+
@io_thread.join
|
100
|
+
end
|
101
|
+
|
102
|
+
def run_spooler
|
103
|
+
loop do
|
104
|
+
spooled = []
|
105
|
+
next_flush = Time.now.to_i + @options[:idle_timeout]
|
106
|
+
|
107
|
+
# The spooler loop
|
108
|
+
begin
|
109
|
+
loop do
|
110
|
+
event = @event_queue.pop next_flush - Time.now.to_i
|
111
|
+
spooled.push(event)
|
112
|
+
break if spooled.length >= @options[:spool_size]
|
113
|
+
end
|
114
|
+
rescue TimeoutError
|
115
|
+
# Hit timeout but no events, keep waiting
|
116
|
+
next if spooled.length == 0
|
117
|
+
end
|
118
|
+
|
119
|
+
# Pass through to io_control but only if we're ready to send
|
120
|
+
@send_mutex.synchronize do
|
121
|
+
@send_cond.wait(@send_mutex) unless @send_ready
|
122
|
+
@send_ready = false
|
123
|
+
@io_control << ['E', spooled]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
rescue ClientShutdownSignal
|
127
|
+
# Just shutdown
|
128
|
+
0
|
129
|
+
end
|
130
|
+
|
131
|
+
def run_io
|
132
|
+
# TODO: Make keepalive configurable?
|
133
|
+
@keepalive_timeout = 1800
|
134
|
+
|
135
|
+
# TODO: Make pending payload max configurable?
|
136
|
+
max_pending_payloads = 100
|
137
|
+
|
138
|
+
retry_payload = nil
|
139
|
+
|
140
|
+
can_send = true
|
141
|
+
|
142
|
+
loop do
|
143
|
+
# Reconnect loop
|
144
|
+
@client.connect @io_control
|
145
|
+
|
146
|
+
reset_keepalive
|
147
|
+
|
148
|
+
# Capture send exceptions
|
149
|
+
begin
|
150
|
+
# IO loop
|
151
|
+
loop do
|
152
|
+
catch :keepalive do
|
153
|
+
begin
|
154
|
+
action = @io_control.pop @keepalive_next - Time.now.to_i
|
155
|
+
|
156
|
+
# Process the action
|
157
|
+
case action[0]
|
158
|
+
when 'S'
|
159
|
+
# If we're flushing through the pending, pick from there
|
160
|
+
unless retry_payload.nil?
|
161
|
+
# Regenerate data if we need to
|
162
|
+
retry_payload.data = buffer_jdat_data(retry_payload.events, retry_payload.nonce) if retry_payload.data == nil
|
163
|
+
|
164
|
+
# Send and move onto next
|
165
|
+
@client.send 'JDAT', retry_payload.data
|
166
|
+
|
167
|
+
retry_payload = retry_payload.next
|
168
|
+
throw :keepalive
|
169
|
+
end
|
170
|
+
|
171
|
+
# Ready to send, allow spooler to pass us something
|
172
|
+
@send_mutex.synchronize do
|
173
|
+
@send_ready = true
|
174
|
+
@send_cond.signal
|
175
|
+
end
|
176
|
+
|
177
|
+
can_send = true
|
178
|
+
when 'E'
|
179
|
+
# If we have too many pending payloads, pause the IO
|
180
|
+
if @pending_payloads.length + 1 >= max_pending_payloads
|
181
|
+
@client.pause_send
|
182
|
+
end
|
183
|
+
|
184
|
+
# Received some events - send them
|
185
|
+
send_jdat action[1]
|
186
|
+
|
187
|
+
# The send action will trigger another "S" if we have more send buffer
|
188
|
+
can_send = false
|
189
|
+
when 'R'
|
190
|
+
# Received a message
|
191
|
+
signature, message = action[1..2]
|
192
|
+
case signature
|
193
|
+
when 'PONG'
|
194
|
+
process_pong message
|
195
|
+
when 'ACKN'
|
196
|
+
process_ackn message
|
197
|
+
else
|
198
|
+
# Unknown message - only listener is allowed to respond with a "????" message
|
199
|
+
# TODO: What should we do? Just ignore for now and let timeouts conquer
|
200
|
+
end
|
201
|
+
when 'F'
|
202
|
+
# Reconnect, an error occurred
|
203
|
+
break
|
204
|
+
end
|
205
|
+
rescue TimeoutError
|
206
|
+
# Keepalive timeout hit, send a PING unless we were awaiting a PONG
|
207
|
+
if @pending_ping
|
208
|
+
# Timed out, break into reconnect
|
209
|
+
raise TimeoutError
|
210
|
+
end
|
211
|
+
|
212
|
+
# Is send full? can_send will be false if so
|
213
|
+
# We should've started receiving ACK by now so time out
|
214
|
+
raise TimeoutError unless can_send
|
215
|
+
|
216
|
+
# Send PING
|
217
|
+
send_ping
|
218
|
+
|
219
|
+
# We may have filled send buffer
|
220
|
+
can_send = false
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# Reset keepalive timeout
|
225
|
+
reset_keepalive
|
226
|
+
end
|
227
|
+
rescue ClientProtocolError => e
|
228
|
+
# Reconnect required due to a protocol error
|
229
|
+
@logger.warn("[LogCourierClient] Protocol error: #{e}") unless @logger.nil?
|
230
|
+
rescue TimeoutError
|
231
|
+
# Reconnect due to timeout
|
232
|
+
@logger.warn('[LogCourierClient] Timeout occurred') unless @logger.nil?
|
233
|
+
rescue ClientShutdownSignal
|
234
|
+
# Shutdown, break out
|
235
|
+
break
|
236
|
+
rescue => e
|
237
|
+
# Unknown error occurred
|
238
|
+
@logger.warn("[LogCourierClient] Unknown error: #{e}") unless @logger.nil?
|
239
|
+
@logger.warn("[LogCourierClient] #{e.backtrace}: #{e.message} (#{e.class})") unless @logger.nil?
|
240
|
+
end
|
241
|
+
|
242
|
+
# Disconnect and retry payloads
|
243
|
+
@client.disconnect
|
244
|
+
retry_payload = @first_payload
|
245
|
+
|
246
|
+
# TODO: Make reconnect time configurable?
|
247
|
+
sleep 5
|
248
|
+
end
|
249
|
+
|
250
|
+
@client.disconnect
|
251
|
+
end
|
252
|
+
|
253
|
+
def reset_keepalive
|
254
|
+
@keepalive_next = Time.now.to_i + @keepalive_timeout
|
255
|
+
end
|
256
|
+
|
257
|
+
def generate_nonce
|
258
|
+
(0...16).map { rand(256).chr }.join("")
|
259
|
+
end
|
260
|
+
|
261
|
+
def send_ping
|
262
|
+
# Send it
|
263
|
+
@client.send 'PING', ''
|
264
|
+
end
|
265
|
+
|
266
|
+
def send_jdat(events)
|
267
|
+
# Generate the JSON payload and compress it
|
268
|
+
nonce = generate_nonce
|
269
|
+
data = buffer_jdat_data(events, nonce)
|
270
|
+
|
271
|
+
# Save the pending payload
|
272
|
+
payload = PendingPayload.new(
|
273
|
+
:events => events,
|
274
|
+
:nonce => nonce,
|
275
|
+
:data => data
|
276
|
+
)
|
277
|
+
|
278
|
+
@pending_payloads[nonce] = payload
|
279
|
+
|
280
|
+
if @first_payload.nil?
|
281
|
+
@first_payload = payload
|
282
|
+
@last_payload = payload
|
283
|
+
else
|
284
|
+
@last_payload.next = payload
|
285
|
+
@last_payload = payload
|
286
|
+
end
|
287
|
+
|
288
|
+
# Send it
|
289
|
+
@client.send 'JDAT', payload.data
|
290
|
+
end
|
291
|
+
|
292
|
+
def buffer_jdat_data(events, nonce)
|
293
|
+
buffer = Zlib::Deflate.new
|
294
|
+
|
295
|
+
# Write each event in JSON format
|
296
|
+
events.each do |event|
|
297
|
+
buffer_jdat_data_event(buffer, event)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Generate and return the message
|
301
|
+
nonce + buffer.flush(Zlib::FINISH)
|
302
|
+
end
|
303
|
+
|
304
|
+
def buffer_jdat_data_event(buffer, event)
|
305
|
+
json_data = @json_adapter.dump(event)
|
306
|
+
|
307
|
+
# Add length and then the data
|
308
|
+
buffer << [json_data.length].pack('N') << json_data
|
309
|
+
end
|
310
|
+
|
311
|
+
def process_pong(message)
|
312
|
+
# Sanity
|
313
|
+
if message.length != 0
|
314
|
+
raise ClientProtocolError, "Unexpected data attached to pong message (#{message.length})"
|
315
|
+
end
|
316
|
+
|
317
|
+
# No longer pending a PONG
|
318
|
+
@ping_pending = false
|
319
|
+
end
|
320
|
+
|
321
|
+
def process_ackn(message)
|
322
|
+
# Sanity
|
323
|
+
if message.length != 20
|
324
|
+
raise ClientProtocolError, "ACKN message size invalid (#{message.length})"
|
325
|
+
end
|
326
|
+
|
327
|
+
# Grab nonce
|
328
|
+
sequence, nonce = message[0...4].unpack('N').first, message[4..-1]
|
329
|
+
|
330
|
+
# Find the payload - skip if we couldn't as it will just a duplicated ACK
|
331
|
+
return unless @pending_payloads.key?(nonce)
|
332
|
+
|
333
|
+
payload = @pending_payloads[nonce]
|
334
|
+
|
335
|
+
# Full ACK?
|
336
|
+
# TODO: protocol error if sequence too large?
|
337
|
+
if sequence >= payload.events.length
|
338
|
+
@client.resume_send if @client.send_paused?
|
339
|
+
|
340
|
+
@pending_payloads.delete nonce
|
341
|
+
payload.previous.next = payload.next
|
342
|
+
else
|
343
|
+
# Partial ACK - only process if something was actually processed
|
344
|
+
if sequence > payload.ack_events
|
345
|
+
payload.ack_events = sequence
|
346
|
+
payload.events = payload.events[0...sequence]
|
347
|
+
payload.data = nil
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Copyright 2014 Jason Woods.
|
4
|
+
#
|
5
|
+
# This file is a modification of code from Logstash Forwarder.
|
6
|
+
# Copyright 2012-2013 Jordan Sissel and contributors.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
|
20
|
+
require 'openssl'
|
21
|
+
require 'socket'
|
22
|
+
require 'thread'
|
23
|
+
|
24
|
+
module LogCourier
|
25
|
+
# TLS transport implementation
|
26
|
+
class ClientTls
|
27
|
+
def initialize(options = {})
|
28
|
+
@options = {
|
29
|
+
logger: nil,
|
30
|
+
port: nil,
|
31
|
+
addresses: [],
|
32
|
+
ssl_ca: nil,
|
33
|
+
ssl_certificate: nil,
|
34
|
+
ssl_key: nil,
|
35
|
+
ssl_key_passphrase: nil
|
36
|
+
}.merge!(options)
|
37
|
+
|
38
|
+
@logger = @options[:logger]
|
39
|
+
|
40
|
+
[:port, :ssl_ca].each do |k|
|
41
|
+
raise "[LogCourierClient] '#{k}' is required" if @options[k].nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
raise '[LogCourierClient] \'addresses\' must contain at least one address' if @options[:addresses].empty?
|
45
|
+
|
46
|
+
c = 0
|
47
|
+
[:ssl_certificate, :ssl_key].each do
|
48
|
+
c += 1
|
49
|
+
end
|
50
|
+
|
51
|
+
raise '[LogCourierClient] \'ssl_certificate\' and \'ssl_key\' must be specified together' if c == 1
|
52
|
+
end
|
53
|
+
|
54
|
+
def connect(io_control)
|
55
|
+
begin
|
56
|
+
tls_connect
|
57
|
+
rescue ClientShutdownSignal
|
58
|
+
raise
|
59
|
+
rescue
|
60
|
+
# TODO: Make this configurable
|
61
|
+
sleep 5
|
62
|
+
retry
|
63
|
+
end
|
64
|
+
|
65
|
+
@send_q = SizedQueue.new 1
|
66
|
+
@send_paused = false
|
67
|
+
|
68
|
+
@send_thread = Thread.new do
|
69
|
+
run_send io_control
|
70
|
+
end
|
71
|
+
@recv_thread = Thread.new do
|
72
|
+
run_recv io_control
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def disconnect
|
77
|
+
@send_thread.raise ClientShutdownSignal
|
78
|
+
@send_thread.join
|
79
|
+
@recv_thread.raise ClientShutdownSignal
|
80
|
+
@recv_thread.join
|
81
|
+
end
|
82
|
+
|
83
|
+
def run_send(io_control)
|
84
|
+
# Ask for something to send
|
85
|
+
io_control << ['S']
|
86
|
+
|
87
|
+
# If paused, we still accept message to send, but we don't release "S" to ask for more
|
88
|
+
# As soon as we resume we then release "S" to ask for more
|
89
|
+
paused = false
|
90
|
+
|
91
|
+
loop do
|
92
|
+
# Wait for data and send when we get it
|
93
|
+
message = @send_q.pop
|
94
|
+
|
95
|
+
# A nil is a pause/resume
|
96
|
+
if message.nil?
|
97
|
+
if paused
|
98
|
+
paused = false
|
99
|
+
io_control << ['S']
|
100
|
+
else
|
101
|
+
paused = true
|
102
|
+
next
|
103
|
+
end
|
104
|
+
else
|
105
|
+
# Ask for more to send while we send this one
|
106
|
+
io_control << ['S'] unless paused
|
107
|
+
|
108
|
+
@ssl_client.write message
|
109
|
+
end
|
110
|
+
end
|
111
|
+
rescue OpenSSL::SSL::SSLError, IOError, Errno::ECONNRESET => e
|
112
|
+
@logger.warn("[LogCourierClient] SSL write error: #{e}") unless @logger.nil?
|
113
|
+
io_control << ['F']
|
114
|
+
rescue ClientShutdownSignal
|
115
|
+
# Just shutdown
|
116
|
+
rescue => e
|
117
|
+
@logger.warn("[LogCourierClient] Unknown SSL write error: #{e}") unless @logger.nil?
|
118
|
+
@logger.warn("[LogCourierClient] #{e.backtrace}: #{e.message} (#{e.class})") unless @logger.nil?
|
119
|
+
io_control << ['F']
|
120
|
+
end
|
121
|
+
|
122
|
+
def run_recv(io_control)
|
123
|
+
loop do
|
124
|
+
# Grab a header
|
125
|
+
header = @ssl_client.read(8)
|
126
|
+
raise EOFError if header.nil?
|
127
|
+
|
128
|
+
# Decode signature and length
|
129
|
+
signature, length = header.unpack('A4N')
|
130
|
+
|
131
|
+
if length > 1048576
|
132
|
+
# Too big raise error
|
133
|
+
@logger.warn("[LogCourierClient] Invalid message: data too big (#{length})") unless @logger.nil?
|
134
|
+
io_control << ['F']
|
135
|
+
break
|
136
|
+
end
|
137
|
+
|
138
|
+
# Read remainder
|
139
|
+
message = @ssl_client.read(length)
|
140
|
+
|
141
|
+
# Pass through to receive
|
142
|
+
io_control << ['R', signature, message]
|
143
|
+
end
|
144
|
+
rescue OpenSSL::SSL::SSLError, IOError, Errno::ECONNRESET => e
|
145
|
+
@logger.warn("[LogCourierClient] SSL read error: #{e}") unless @logger.nil?
|
146
|
+
io_control << ['F']
|
147
|
+
rescue EOFError
|
148
|
+
@logger.warn("[LogCourierClient] Connection closed by server") unless @logger.nil?
|
149
|
+
io_control << ['F']
|
150
|
+
rescue ClientShutdownSignal
|
151
|
+
# Just shutdown
|
152
|
+
rescue => e
|
153
|
+
@logger.warn("[LogCourierClient] Unknown SSL read error: #{e}") unless @logger.nil?
|
154
|
+
@logger.warn("[LogCourierClient] #{e.backtrace}: #{e.message} (#{e.class})") unless @logger.nil?
|
155
|
+
io_control << ['F']
|
156
|
+
end
|
157
|
+
|
158
|
+
def send(signature, message)
|
159
|
+
# Add to send queue
|
160
|
+
@send_q << [signature, message.length].pack('A4N') + message
|
161
|
+
end
|
162
|
+
|
163
|
+
def pause_send
|
164
|
+
return if @send_paused
|
165
|
+
@send_paused = true
|
166
|
+
@send_q << nil
|
167
|
+
end
|
168
|
+
|
169
|
+
def send_paused
|
170
|
+
@send_paused
|
171
|
+
end
|
172
|
+
|
173
|
+
def resume_send
|
174
|
+
if @send_paused
|
175
|
+
@send_paused = false
|
176
|
+
@send_q << nil
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def tls_connect
|
181
|
+
# TODO: Implement random selection - and don't use separate :port - remember to update post_connection_check too
|
182
|
+
@logger.info("[LogCourierClient] Connecting to #{@options[:addresses][0]}:#{@options[:port]}") unless @logger.nil?
|
183
|
+
tcp_socket = TCPSocket.new(@options[:addresses][0], @options[:port])
|
184
|
+
|
185
|
+
ssl = OpenSSL::SSL::SSLContext.new
|
186
|
+
|
187
|
+
unless @options[:ssl_certificate].nil?
|
188
|
+
ssl.cert = OpenSSL::X509::Certificate.new(File.read(@options[:ssl_certificate]))
|
189
|
+
ssl.key = OpenSSL::PKey::RSA.new(File.read(@options[:ssl_key]), @options[:ssl_key_passphrase])
|
190
|
+
end
|
191
|
+
|
192
|
+
cert_store = OpenSSL::X509::Store.new
|
193
|
+
cert_store.add_file(@options[:ssl_ca])
|
194
|
+
#ssl.cert_store = cert_store
|
195
|
+
ssl.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
196
|
+
|
197
|
+
@ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_socket)
|
198
|
+
|
199
|
+
socket = @ssl_client.connect
|
200
|
+
|
201
|
+
# Verify certificate
|
202
|
+
socket.post_connection_check(@options[:addresses][0])
|
203
|
+
|
204
|
+
@logger.info("[LogCourierClient] Connected successfully") unless @logger.nil?
|
205
|
+
|
206
|
+
socket
|
207
|
+
rescue OpenSSL::SSL::SSLError, IOError, Errno::ECONNRESET => e
|
208
|
+
@logger.warn("[LogCourierClient] Connection to #{@options[:addresses][0]}:#{@options[:port]} failed: #{e}") unless @logger.nil?
|
209
|
+
rescue ClientShutdownSignal
|
210
|
+
# Just shutdown
|
211
|
+
0
|
212
|
+
rescue => e
|
213
|
+
@logger.warn("[LogCourierClient] Unknown connection failure to #{@options[:addresses][0]}:#{@options[:port]}: #{e}") unless @logger.nil?
|
214
|
+
@logger.warn("[LogCourierClient] #{e.backtrace}: #{e.message} (#{e.class})") unless @logger.nil?
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|