<commit_before>/*
 * Copyright 2013-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "phenom/stream.h"
#include "phenom/openssl.h"
#include "phenom/log.h"
#include <openssl/bio.h>

/* Implements a phenom stream that delegates to an OpenSSL SSL object */

static bool ssl_stm_close(ph_stream_t *stm)
{
  SSL *s = stm->cookie;

  if (s) {
    SSL_free(s);
    stm->cookie = NULL;
  }

  return true;
}

static bool do_ssl_read_or_write(ph_stream_t *stm, bool is_reading,
    const struct iovec *iov, int iovcnt, uint64_t *nread)
{
  int i;
  int res, err;
  unsigned long serr; // NOLINT(runtime/int)
  const char *file;
  int line;
  SSL *s = stm->cookie;

  if (ph_unlikely(s == NULL)) {
    stm->last_err = EBADF;
    return false;
  }

  for (i = 0; i < iovcnt; i++) {
    if (iov[i].iov_len == 0) {
      continue;
    }

    if (is_reading) {
      res = SSL_read(s, iov[i].iov_base, iov[i].iov_len);
    } else {
      res = SSL_write(s, iov[i].iov_base, iov[i].iov_len);
    }

    if (res > 0) {
      if (nread) {
        *nread = res;
      }
      return true;
    }
    err = SSL_get_error(s, res);

    switch (err) {
      case SSL_ERROR_WANT_READ:
        stm->need_mask |= PH_IOMASK_READ;
        stm->last_err = EAGAIN;
        return false;

      case SSL_ERROR_WANT_WRITE:
        stm->need_mask |= PH_IOMASK_WRITE;
        stm->last_err = EAGAIN;
        return false;

      default:
        stm->last_err = EIO;
        // TODO(wez): maybe capture and track the error stack?
        // We must consume it here regardless
        while ((serr = ERR_get_error_line(&file, &line)) != 0) {
          char ebuf[120];
          ERR_error_string_n(serr, ebuf, sizeof(ebuf));
          ph_log(PH_LOG_ERR, "SSL err: %s:%d %lu %s", file, line, serr, ebuf);
        }
        return false;
    }<commit_msg>Downgrade ssl errors to INFO level<commit_after>/*
 * Copyright 2013-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "phenom/stream.h"
#include "phenom/openssl.h"
#include "phenom/log.h"
#include <openssl/bio.h>

/* Implements a phenom stream that delegates to an OpenSSL SSL object */

static bool ssl_stm_close(ph_stream_t *stm)
{
  SSL *s = stm->cookie;

  if (s) {
    SSL_free(s);
    stm->cookie = NULL;
  }

  return true;
}

static bool do_ssl_read_or_write(ph_stream_t *stm, bool is_reading,
    const struct iovec *iov, int iovcnt, uint64_t *nread)
{
  int i;
  int res, err;
  unsigned long serr; // NOLINT(runtime/int)
  const char *file;
  int line;
  SSL *s = stm->cookie;

  if (ph_unlikely(s == NULL)) {
    stm->last_err = EBADF;
    return false;
  }

  for (i = 0; i < iovcnt; i++) {
    if (iov[i].iov_len == 0) {
      continue;
    }

    if (is_reading) {
      res = SSL_read(s, iov[i].iov_base, iov[i].iov_len);
    } else {
      res = SSL_write(s, iov[i].iov_base, iov[i].iov_len);
    }

    if (res > 0) {
      if (nread) {
        *nread = res;
      }
      return true;
    }
    err = SSL_get_error(s, res);

    switch (err) {
      case SSL_ERROR_WANT_READ:
        stm->need_mask |= PH_IOMASK_READ;
        stm->last_err = EAGAIN;
        return false;

      case SSL_ERROR_WANT_WRITE:
        stm->need_mask |= PH_IOMASK_WRITE;
        stm->last_err = EAGAIN;
        return false;

      default:
        stm->last_err = EIO;
        // TODO(wez): maybe capture and track the error stack?
        // We must consume it here regardless
        while ((serr = ERR_get_error_line(&file, &line)) != 0) {
          char ebuf[120];
          ERR_error_string_n(serr, ebuf, sizeof(ebuf));
          ph_log(PH_LOG_INFO, "SSL err: %s:%d %lu %s", file, line, serr, ebuf);
        }
        return false;
    }
{'fraction_non_alphanumeric': 0.11799410029498525, 'fraction_numerical': 0.007163927517909819, 'mean_word_length': 2.612633181126332, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2461019', 'n_tokens_mistral': 1708, 'n_tokens_neox': 1668, 'n_words': 493}