Path: blob/master/runtime/compiler/net/ClientStream.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2018, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* 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-exception20*******************************************************************************/2122#include "ClientStream.hpp"23#include "control/CompilationRuntime.hpp"24#include "control/Options.hpp"25#include "env/VerboseLog.hpp"26#include "net/LoadSSLLibs.hpp"27#include <sys/types.h>28#include <sys/socket.h>29#include <sys/un.h>30#include <netdb.h>31#include <netinet/in.h>32#include <netinet/tcp.h> /* for TCP_NODELAY option */33#include <fcntl.h>34#include <arpa/inet.h>35#include <stdio.h>36#include <stdlib.h>37#include <unistd.h> /// gethostname, read, write38#include <openssl/err.h>3940namespace JITServer41{42int ClientStream::_numConnectionsOpened = 0;43int ClientStream::_numConnectionsClosed = 0;4445// used for checking server compatibility46int ClientStream::_incompatibilityCount = 0;47uint64_t ClientStream::_incompatibleStartTime = 0;48const uint64_t ClientStream::RETRY_COMPATIBILITY_INTERVAL_MS = 10000; //ms49const int ClientStream::INCOMPATIBILITY_COUNT_LIMIT = 1; // This needs to be smaller than the recompilation retry count (3)5051// Create SSL context, load certs and keys. Only needs to be done once.52// This is called during startup from rossa.cpp53int ClientStream::static_init(TR::PersistentInfo *info)54{55if (!CommunicationStream::useSSL())56return 0;5758CommunicationStream::initSSL();5960SSL_CTX *ctx = (*OSSL_CTX_new)((*OSSLv23_client_method)());61if (!ctx)62{63perror("can't create SSL context");64(*OERR_print_errors_fp)(stderr);65return -1;66}6768if ((*OSSL_CTX_set_ecdh_auto)(ctx, 1) != 1)69{70perror("failed to configure SSL ecdh");71(*OERR_print_errors_fp)(stderr);72return -1;73}7475TR::CompilationInfo *compInfo = TR::CompilationInfo::get();76auto &sslKeys = compInfo->getJITServerSslKeys();77auto &sslCerts = compInfo->getJITServerSslCerts();78auto &sslRootCerts = compInfo->getJITServerSslRootCerts();7980// We could also set up keys and certs here, if it's necessary to use TLS client keys81// it's not needed for a basic setup.82TR_ASSERT_FATAL(sslKeys.size() == 0 && sslCerts.size() == 0, "client keypairs are not yet supported, use a root cert chain instead");8384// Parse and set certificate chain85BIO *certMem = (*OBIO_new_mem_buf)(&sslRootCerts[0], sslRootCerts.size());86if (!certMem)87{88perror("cannot create memory buffer for cert (OOM?)");89(*OERR_print_errors_fp)(stderr);90return -1;91}92STACK_OF(X509_INFO) *certificates = (*OPEM_X509_INFO_read_bio)(certMem, NULL, NULL, NULL);93if (!certificates)94{95perror("cannot parse cert");96(*OERR_print_errors_fp)(stderr);97return -1;98}99X509_STORE *certStore = (*OSSL_CTX_get_cert_store)(ctx);100if (!certStore)101{102perror("cannot get cert store");103(*OERR_print_errors_fp)(stderr);104return -1;105}106107// add all certificates in the chain to the cert store108for (size_t i = 0; i < (*Osk_X509_INFO_num)(certificates); i++)109{110X509_INFO *certInfo = (*Osk_X509_INFO_value)(certificates, i);111if (certInfo->x509)112(*OX509_STORE_add_cert)(certStore, certInfo->x509);113if (certInfo->crl)114(*OX509_STORE_add_crl)(certStore, certInfo->crl);115}116(*Osk_X509_INFO_pop_free)(certificates, (*OX509_INFO_free));117118// verify server identity using standard method119(*OSSL_CTX_set_verify)(ctx, SSL_VERIFY_PEER, NULL);120121_sslCtx = ctx;122123if (TR::Options::getVerboseOption(TR_VerboseJITServer))124TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "Successfully initialized SSL context (%s) \n", (*OOpenSSL_version)(0));125return 0;126}127128SSL_CTX *ClientStream::_sslCtx = NULL;129130int openConnection(const std::string &address, uint32_t port, uint32_t timeoutMs)131{132// TODO consider support for IPv6133struct addrinfo hints;134memset(&hints, 0, sizeof(hints));135hints.ai_family = AF_INET; // Allow IPv4 only; could use AF_UNSPEC to allow IPv6 too136hints.ai_socktype = SOCK_STREAM;137hints.ai_flags = 0;138hints.ai_protocol = 0; // Any protocol139140char portName[12];141int r = snprintf(portName, 12, "%d", port);142if (r < 0 || r > 11)143throw StreamFailure("snprintf failed");144145struct addrinfo *addrList = NULL;146int res = getaddrinfo(address.c_str(), portName, &hints, &addrList);147if (res != 0)148{149// Can use gai_strerror(res) to show error code150throw StreamFailure("Cannot resolve server name");151}152struct addrinfo *pAddr;153int sockfd = -1;154for (pAddr = addrList; pAddr; pAddr = pAddr->ai_next)155{156sockfd = socket(pAddr->ai_family, pAddr->ai_socktype, pAddr->ai_protocol);157if (sockfd >= 0)158break; // Use the first address for which a socket could be created159// Try next address160}161if (sockfd < 0)162{163freeaddrinfo(addrList);164throw StreamFailure("Cannot create socket for JITServer");165}166167int flag = 1;168if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&flag, sizeof(flag)) < 0)169{170freeaddrinfo(addrList);171close(sockfd);172throw StreamFailure("Cannot set option SO_KEEPALIVE on socket");173}174175struct linger lingerVal = {1, 2}; // linger 2 seconds176if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (void *)&lingerVal, sizeof(lingerVal)) < 0)177{178freeaddrinfo(addrList);179close(sockfd);180throw StreamFailure("Cannot set option SO_LINGER on socket");181}182183struct timeval timeout = {(timeoutMs / 1000), ((timeoutMs % 1000) * 1000)};184if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout)) < 0)185{186freeaddrinfo(addrList);187close(sockfd);188throw StreamFailure("Cannot set option SO_RCVTIMEO on socket");189}190191if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout)) < 0)192{193freeaddrinfo(addrList);194close(sockfd);195throw StreamFailure("Cannot set option SO_SNDTIMEO on socket");196}197198if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) < 0)199{200freeaddrinfo(addrList);201close(sockfd);202throw StreamFailure("Cannot set option TCP_NODELAY on socket");203}204if (connect(sockfd, pAddr->ai_addr, pAddr->ai_addrlen) < 0)205{206freeaddrinfo(addrList);207close(sockfd);208throw StreamFailure("Connect failed");209}210freeaddrinfo(addrList);211return sockfd;212}213214static BIO *215openSSLConnection(SSL_CTX *ctx, int connfd)216{217if (!ctx)218return NULL;219220BIO *bio = (*OBIO_new_ssl)(ctx, true);221if (!bio)222{223(*OERR_print_errors_fp)(stderr);224throw JITServer::StreamFailure("Failed to make new BIO");225}226227SSL *ssl = NULL;228if ((*OBIO_ctrl)(bio, BIO_C_GET_SSL, false, (char *)&ssl) != 1) // BIO_get_ssl(bio, &ssl)229{230(*OERR_print_errors_fp)(stderr);231(*OBIO_free_all)(bio);232throw JITServer::StreamFailure("Failed to get BIO SSL");233}234235if ((*OSSL_set_fd)(ssl, connfd) != 1)236{237(*OERR_print_errors_fp)(stderr);238(*OBIO_free_all)(bio);239throw JITServer::StreamFailure("Cannot set file descriptor for SSL");240}241242if ((*OSSL_connect)(ssl) != 1)243{244(*OERR_print_errors_fp)(stderr);245(*OBIO_free_all)(bio);246throw JITServer::StreamFailure("Failed to SSL_connect");247}248249X509 *cert = (*OSSL_get_peer_certificate)(ssl);250if (!cert)251{252(*OERR_print_errors_fp)(stderr);253(*OBIO_free_all)(bio);254throw JITServer::StreamFailure("Server certificate unspecified");255}256(*OX509_free)(cert);257258if (X509_V_OK != (*OSSL_get_verify_result)(ssl))259{260(*OERR_print_errors_fp)(stderr);261(*OBIO_free_all)(bio);262throw JITServer::StreamFailure("Server certificate verification failed");263}264265if (TR::Options::getVerboseOption(TR_VerboseJITServer))266TR_VerboseLog::writeLineLocked(TR_Vlog_JITServer, "SSL connection on socket 0x%x, Version: %s, Cipher: %s\n",267connfd, (*OSSL_get_version)(ssl), (*OSSL_get_cipher)(ssl));268return bio;269}270271ClientStream::ClientStream(TR::PersistentInfo *info)272: CommunicationStream(), _versionCheckStatus(NOT_DONE)273{274int connfd = openConnection(info->getJITServerAddress(), info->getJITServerPort(), info->getSocketTimeout());275BIO *ssl = openSSLConnection(_sslCtx, connfd);276initStream(connfd, ssl);277_numConnectionsOpened++;278}279};280281282