1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.openehealth.ipf.commons.audit.protocol;
17
18
19 import org.openehealth.ipf.commons.audit.AuditContext;
20 import org.openehealth.ipf.commons.audit.AuditException;
21 import org.openehealth.ipf.commons.audit.utils.AuditUtils;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import javax.net.ssl.SSLSocketFactory;
26 import java.io.IOException;
27 import java.io.OutputStream;
28 import java.net.Socket;
29 import java.net.SocketException;
30 import java.nio.charset.StandardCharsets;
31 import java.util.concurrent.atomic.AtomicReference;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class TLSSyslogSenderImpl extends RFC5424Protocol implements AuditTransmissionProtocol {
54
55 private static final Logger LOG = LoggerFactory.getLogger(TLSSyslogSenderImpl.class);
56 private AtomicReference<Socket> socket = new AtomicReference<>();
57
58 public TLSSyslogSenderImpl() {
59 this(AuditUtils.getLocalHostName(), AuditUtils.getProcessId());
60 }
61
62 public TLSSyslogSenderImpl(String sendingHost, String sendingProcess) {
63 super(sendingHost, sendingProcess);
64 }
65
66 @Override
67 public String getTransportName() {
68 return "TLS";
69 }
70
71 private Socket getSocket(AuditContext auditContext) {
72 if (socket.get() == null) socket.compareAndSet(null, getTLSSocket(auditContext));
73 return socket.get();
74 }
75
76 @Override
77 public void send(AuditContext auditContext, String... auditMessages) throws Exception {
78 if (auditMessages != null) {
79 for (String auditMessage : auditMessages) {
80 byte[] msgBytes = getTransportPayload(auditContext.getSendingApplication(), auditMessage);
81 byte[] syslogFrame = String.format("%d ", msgBytes.length).getBytes();
82 LOG.debug("Auditing to {}:{}",
83 auditContext.getAuditRepositoryAddress().getHostAddress(),
84 auditContext.getAuditRepositoryPort());
85 LOG.trace("{}", new String(msgBytes, StandardCharsets.UTF_8));
86 try {
87 doSend(auditContext, syslogFrame, msgBytes);
88 } catch (SocketException e) {
89 try {
90 LOG.info("Failed to use existing TLS socket. Will create a new connection and retry.");
91 socket.set(null);
92 doSend(auditContext, syslogFrame, msgBytes);
93 } catch (Exception exception) {
94 LOG.error("Failed to audit using new TLS socket, giving up - this audit message will be lost.");
95 socket.set(null);
96
97 throw exception;
98 }
99 }
100 }
101 }
102 }
103
104 @Override
105 public void shutdown() {
106 if (socket.get() != null) {
107 try {
108
109 socket.get().close();
110 } catch (IOException ignored) {
111 }
112 }
113 }
114
115 private synchronized void doSend(AuditContext auditContext, byte[] syslogFrame, byte[] msgBytes) throws IOException {
116 Socket socket = getSocket(auditContext);
117 OutputStream out = socket.getOutputStream();
118 out.write(syslogFrame);
119 out.write(msgBytes);
120 out.flush();
121 }
122
123 private Socket getTLSSocket(AuditContext auditContext) {
124 try {
125 return SSLSocketFactory.getDefault()
126 .createSocket(auditContext.getAuditRepositoryAddress(), auditContext.getAuditRepositoryPort());
127 } catch (IOException e) {
128 throw new AuditException(String.format("Could not establish TLS connection to %s:%d",
129 auditContext.getAuditRepositoryAddress().getHostAddress(),
130 auditContext.getAuditRepositoryPort()), e);
131 }
132 }
133
134
135 }