Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/net/ClientStream.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2018, 2022 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "ClientStream.hpp"
24
#include "control/CompilationRuntime.hpp"
25
#include "control/Options.hpp"
26
#include "env/VerboseLog.hpp"
27
#include "net/LoadSSLLibs.hpp"
28
#include <sys/types.h>
29
#include <sys/socket.h>
30
#include <sys/un.h>
31
#include <netdb.h>
32
#include <netinet/in.h>
33
#include <netinet/tcp.h> /* for TCP_NODELAY option */
34
#include <fcntl.h>
35
#include <arpa/inet.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <unistd.h> /// gethostname, read, write
39
#include <openssl/err.h>
40
41
namespace JITServer
42
{
43
int ClientStream::_numConnectionsOpened = 0;
44
int ClientStream::_numConnectionsClosed = 0;
45
46
// used for checking server compatibility
47
int ClientStream::_incompatibilityCount = 0;
48
uint64_t ClientStream::_incompatibleStartTime = 0;
49
const uint64_t ClientStream::RETRY_COMPATIBILITY_INTERVAL_MS = 10000; //ms
50
const int ClientStream::INCOMPATIBILITY_COUNT_LIMIT = 1; // This needs to be smaller than the recompilation retry count (3)
51
52
// Create SSL context, load certs and keys. Only needs to be done once.
53
// This is called during startup from rossa.cpp
54
int ClientStream::static_init(TR::PersistentInfo *info)
55
{
56
if (!CommunicationStream::useSSL())
57
return 0;
58
59
CommunicationStream::initSSL();
60
61
SSL_CTX *ctx = (*OSSL_CTX_new)((*OSSLv23_client_method)());
62
if (!ctx)
63
{
64
perror("can't create SSL context");
65
(*OERR_print_errors_fp)(stderr);
66
return -1;
67
}
68
69
if ((*OSSL_CTX_set_ecdh_auto)(ctx, 1) != 1)
70
{
71
perror("failed to configure SSL ecdh");
72
(*OERR_print_errors_fp)(stderr);
73
return -1;
74
}
75
76
TR::CompilationInfo *compInfo = TR::CompilationInfo::get();
77
auto &sslKeys = compInfo->getJITServerSslKeys();
78
auto &sslCerts = compInfo->getJITServerSslCerts();
79
auto &sslRootCerts = compInfo->getJITServerSslRootCerts();
80
81
// We could also set up keys and certs here, if it's necessary to use TLS client keys
82
// it's not needed for a basic setup.
83
TR_ASSERT_FATAL(sslKeys.size() == 0 && sslCerts.size() == 0, "client keypairs are not yet supported, use a root cert chain instead");
84
85
// Parse and set certificate chain
86
BIO *certMem = (*OBIO_new_mem_buf)(&sslRootCerts[0], sslRootCerts.size());
87
if (!certMem)
88
{
89
perror("cannot create memory buffer for cert (OOM?)");
90
(*OERR_print_errors_fp)(stderr);
91
return -1;
92
}
93
STACK_OF(X509_INFO) *certificates = (*OPEM_X509_INFO_read_bio)(certMem, NULL, NULL, NULL);
94
if (!certificates)
95
{
96
perror("cannot parse cert");
97
(*OERR_print_errors_fp)(stderr);
98
return -1;
99
}
100
X509_STORE *certStore = (*OSSL_CTX_get_cert_store)(ctx);
101
if (!certStore)
102
{
103
perror("cannot get cert store");
104
(*OERR_print_errors_fp)(stderr);
105
return -1;
106
}
107
108
// add all certificates in the chain to the cert store
109
for (size_t i = 0; i < (*Osk_X509_INFO_num)(certificates); i++)
110
{
111
X509_INFO *certInfo = (*Osk_X509_INFO_value)(certificates, i);
112
if (certInfo->x509)
113
(*OX509_STORE_add_cert)(certStore, certInfo->x509);
114
if (certInfo->crl)
115
(*OX509_STORE_add_crl)(certStore, certInfo->crl);
116
}
117
(*Osk_X509_INFO_pop_free)(certificates, (*OX509_INFO_free));
118
119
// verify server identity using standard method
120
(*OSSL_CTX_set_verify)(ctx, SSL_VERIFY_PEER, NULL);
121
122
_sslCtx = ctx;
123
124
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
125
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "Successfully initialized SSL context (%s) \n", (*OOpenSSL_version)(0));
126
return 0;
127
}
128
129
SSL_CTX *ClientStream::_sslCtx = NULL;
130
131
int openConnection(const std::string &address, uint32_t port, uint32_t timeoutMs)
132
{
133
// TODO consider support for IPv6
134
struct addrinfo hints;
135
memset(&hints, 0, sizeof(hints));
136
hints.ai_family = AF_INET; // Allow IPv4 only; could use AF_UNSPEC to allow IPv6 too
137
hints.ai_socktype = SOCK_STREAM;
138
hints.ai_flags = 0;
139
hints.ai_protocol = 0; // Any protocol
140
141
char portName[12];
142
int r = snprintf(portName, 12, "%d", port);
143
if (r < 0 || r > 11)
144
throw StreamFailure("snprintf failed");
145
146
struct addrinfo *addrList = NULL;
147
int res = getaddrinfo(address.c_str(), portName, &hints, &addrList);
148
if (res != 0)
149
{
150
// Can use gai_strerror(res) to show error code
151
throw StreamFailure("Cannot resolve server name");
152
}
153
struct addrinfo *pAddr;
154
int sockfd = -1;
155
for (pAddr = addrList; pAddr; pAddr = pAddr->ai_next)
156
{
157
sockfd = socket(pAddr->ai_family, pAddr->ai_socktype, pAddr->ai_protocol);
158
if (sockfd >= 0)
159
break; // Use the first address for which a socket could be created
160
// Try next address
161
}
162
if (sockfd < 0)
163
{
164
freeaddrinfo(addrList);
165
throw StreamFailure("Cannot create socket for JITServer");
166
}
167
168
int flag = 1;
169
if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&flag, sizeof(flag)) < 0)
170
{
171
freeaddrinfo(addrList);
172
close(sockfd);
173
throw StreamFailure("Cannot set option SO_KEEPALIVE on socket");
174
}
175
176
struct linger lingerVal = {1, 2}; // linger 2 seconds
177
if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (void *)&lingerVal, sizeof(lingerVal)) < 0)
178
{
179
freeaddrinfo(addrList);
180
close(sockfd);
181
throw StreamFailure("Cannot set option SO_LINGER on socket");
182
}
183
184
struct timeval timeout = {(timeoutMs / 1000), ((timeoutMs % 1000) * 1000)};
185
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout)) < 0)
186
{
187
freeaddrinfo(addrList);
188
close(sockfd);
189
throw StreamFailure("Cannot set option SO_RCVTIMEO on socket");
190
}
191
192
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout)) < 0)
193
{
194
freeaddrinfo(addrList);
195
close(sockfd);
196
throw StreamFailure("Cannot set option SO_SNDTIMEO on socket");
197
}
198
199
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) < 0)
200
{
201
freeaddrinfo(addrList);
202
close(sockfd);
203
throw StreamFailure("Cannot set option TCP_NODELAY on socket");
204
}
205
if (connect(sockfd, pAddr->ai_addr, pAddr->ai_addrlen) < 0)
206
{
207
freeaddrinfo(addrList);
208
close(sockfd);
209
throw StreamFailure("Connect failed");
210
}
211
freeaddrinfo(addrList);
212
return sockfd;
213
}
214
215
static BIO *
216
openSSLConnection(SSL_CTX *ctx, int connfd)
217
{
218
if (!ctx)
219
return NULL;
220
221
BIO *bio = (*OBIO_new_ssl)(ctx, true);
222
if (!bio)
223
{
224
(*OERR_print_errors_fp)(stderr);
225
throw JITServer::StreamFailure("Failed to make new BIO");
226
}
227
228
SSL *ssl = NULL;
229
if ((*OBIO_ctrl)(bio, BIO_C_GET_SSL, false, (char *)&ssl) != 1) // BIO_get_ssl(bio, &ssl)
230
{
231
(*OERR_print_errors_fp)(stderr);
232
(*OBIO_free_all)(bio);
233
throw JITServer::StreamFailure("Failed to get BIO SSL");
234
}
235
236
if ((*OSSL_set_fd)(ssl, connfd) != 1)
237
{
238
(*OERR_print_errors_fp)(stderr);
239
(*OBIO_free_all)(bio);
240
throw JITServer::StreamFailure("Cannot set file descriptor for SSL");
241
}
242
243
if ((*OSSL_connect)(ssl) != 1)
244
{
245
(*OERR_print_errors_fp)(stderr);
246
(*OBIO_free_all)(bio);
247
throw JITServer::StreamFailure("Failed to SSL_connect");
248
}
249
250
X509 *cert = (*OSSL_get_peer_certificate)(ssl);
251
if (!cert)
252
{
253
(*OERR_print_errors_fp)(stderr);
254
(*OBIO_free_all)(bio);
255
throw JITServer::StreamFailure("Server certificate unspecified");
256
}
257
(*OX509_free)(cert);
258
259
if (X509_V_OK != (*OSSL_get_verify_result)(ssl))
260
{
261
(*OERR_print_errors_fp)(stderr);
262
(*OBIO_free_all)(bio);
263
throw JITServer::StreamFailure("Server certificate verification failed");
264
}
265
266
if (TR::Options::getVerboseOption(TR_VerboseJITServer))
267
TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "SSL connection on socket 0x%x, Version: %s, Cipher: %s\n",
268
connfd, (*OSSL_get_version)(ssl), (*OSSL_get_cipher)(ssl));
269
return bio;
270
}
271
272
ClientStream::ClientStream(TR::PersistentInfo *info)
273
: CommunicationStream(), _versionCheckStatus(NOT_DONE)
274
{
275
int connfd = openConnection(info->getJITServerAddress(), info->getJITServerPort(), info->getSocketTimeout());
276
BIO *ssl = openSSLConnection(_sslCtx, connfd);
277
initStream(connfd, ssl);
278
_numConnectionsOpened++;
279
}
280
};
281
282