<commit_before>/*
 * Based on SSH example code found here:
 *
 * http://git.libssh.org/users/milo/libssh.git/plain/examples/samplesshd-full.c?h=sshd
 *
 * Copyright 2003-2011 <NAME>
 *
 * This file is part of the SSH Library
 *
 * You are free to copy this file, modify it in any way, consider it being public
 * domain. This does not apply to the rest of the library though, but it is
 * allowed to cut-and-paste working code from this file to any license of
 * program.
 *
 * The goal is to show the API in action. It's not a reference on how terminal
 * clients must be made or how a client should react.
 */

#include "config.h"

#include <libssh/libssh.h>
#include <libssh/server.h>
#include <libssh/callbacks.h>

#include <glib.h>

#include <sys/socket.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <poll.h>
#include <pty.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFSIZE          (8 * 1024)

static gint auth_methods = SSH_AUTH_METHOD_PASSWORD;

struct {
  int bind_fd;
  int session_fd;
  ssh_session session;
  ssh_event event;
  ssh_channel channel;
  int childpid;
  const gchar *user;
  const gchar *password;
  GByteArray *buffer;
  gboolean buffer_eof;
} state;

static gboolean
auth_password (const gchar *user,
               const gchar *password)
{
  return g_str_equal (user, state.user) &&
         g_str_equal (password, state.password);
}

static int
fd_data (socket_t fd,
         int revents,
         gpointer user_data)
{
  ssh_channel chan = (ssh_channel)user_data;
  guint8 buf[BUFSIZE];
  gint sz = 0;
  gint bytes = 0;
  gint status;
  gint written;
  static pid_t p = 0;

  if (p != 0)
    return -1;
  if (revents & POLLIN)
    {
      int ws;
      do
        {
          ws = ssh_channel_window_size (chan);
          ws = ws < BUFSIZE ? ws : BUFSIZE;
          if (ws && (bytes = read (fd, buf, ws)) > 0)
            {
              sz += bytes;
              written = ssh_channel_write (chan, buf, bytes);
              if (written != bytes)
                g_assert_not_reached ();
            }
        }
      while (ws > 0 && bytes == BUFSIZE);
    }
  if (revents & (POLLHUP | POLLERR | POLLNVAL))
    {
      ssh_channel_send_eof (chan);
      if ((p = waitpid (state.childpid, &status, WNOHANG)) > 0)
        {
          if (WIFSIGNALED (status))
            ssh_channel_request_send_exit_signal (chan, strsignal (WTERMSIG (status)), 0, "", "");
          else
            ssh_channel_request_send_exit_status (chan, WEXITSTATUS (status));
        }
      g_assert_cmpint (ssh_blocking_flush (state.session, -1), >=, SSH_OK);
      ssh_channel_close (chan);
      ssh_channel_free (chan);
      state.channel = NULL;
      ssh_event_remove_fd (state.event, fd);
      sz = -1;
    }
  else if ((revents & POLLOUT))
    {
      if (state.buffer->len > 0)
        {
          written = write (fd, state.buffer->data, state.buffer->len);
          if (written < 0 && errno != EAGAIN)
            g_critical ("couldn't write: %s", g_strerror (errno));
          if (written > 0)
            g_byte_array_remove_range (state.buffer, 0, written);
        }
      if (state.buffer_eof && state.buffer->len == 0)
        {
          if (shutdown (fd, SHUT_WR) < 0)
            {
              if (errno != EAGAIN)
                g_critical ("couldn't shutdown: %s", g_strerror (errno));
            }
          else<commit_msg>ws: Fix race closing down mock-sshd session/connection<commit_after>/*
 * Based on SSH example code found here:
 *
 * http://git.libssh.org/users/milo/libssh.git/plain/examples/samplesshd-full.c?h=sshd
 *
 * Copyright 2003-2011 <NAME>
 *
 * This file is part of the SSH Library
 *
 * You are free to copy this file, modify it in any way, consider it being public
 * domain. This does not apply to the rest of the library though, but it is
 * allowed to cut-and-paste working code from this file to any license of
 * program.
 *
 * The goal is to show the API in action. It's not a reference on how terminal
 * clients must be made or how a client should react.
 */

#include "config.h"

#include <libssh/libssh.h>
#include <libssh/server.h>
#include <libssh/callbacks.h>

#include <glib.h>

#include <sys/socket.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <poll.h>
#include <pty.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFSIZE          (8 * 1024)

static gint auth_methods = SSH_AUTH_METHOD_PASSWORD;

struct {
  int bind_fd;
  int session_fd;
  ssh_session session;
  ssh_event event;
  ssh_channel channel;
  int childpid;
  const gchar *user;
  const gchar *password;
  GByteArray *buffer;
  gboolean buffer_eof;
} state;

static gboolean
auth_password (const gchar *user,
               const gchar *password)
{
  return g_str_equal (user, state.user) &&
         g_str_equal (password, state.password);
}

static int
fd_data (socket_t fd,
         int revents,
         gpointer user_data)
{
  ssh_channel chan = (ssh_channel)user_data;
  guint8 buf[BUFSIZE];
  gint sz = 0;
  gint bytes = 0;
  gint status;
  gint written;
  static pid_t p = 0;

  if (p != 0)
    return -1;
  if (revents & POLLIN)
    {
      int ws;
      do
        {
          ws = ssh_channel_window_size (chan);
          ws = ws < BUFSIZE ? ws : BUFSIZE;
          if (ws && (bytes = read (fd, buf, ws)) > 0)
            {
              sz += bytes;
              written = ssh_channel_write (chan, buf, bytes);
              if (written != bytes)
                g_assert_not_reached ();
            }
        }
      while (ws > 0 && bytes == BUFSIZE);
    }
  if (revents & (POLLHUP | POLLERR | POLLNVAL))
    {
      ssh_channel_send_eof (chan);
      if ((p = waitpid (state.childpid, &status, WNOHANG)) > 0)
        {
          if (WIFSIGNALED (status))
            ssh_channel_request_send_exit_signal (chan, strsignal (WTERMSIG (status)), 0, "", "");
          else
            ssh_channel_request_send_exit_status (chan, WEXITSTATUS (status));
        }
      g_assert_cmpint (ssh_blocking_flush (state.session, -1), >=, SSH_OK);
      ssh_channel_close (chan);
      ssh_channel_free (chan);
      state.channel = NULL;
      ssh_event_remove_fd (state.event, fd);
      sz = -1;
    }
  else if ((revents & POLLOUT))
    {
      if (state.buffer->len > 0)
        {
          written = write (fd, state.buffer->data, state.buffer->len);
          if (written < 0 && errno != EAGAIN)
            g_critical ("couldn't write: %s", g_strerror (errno));
          if (written > 0)
            g_byte_array_remove_range (state.buffer, 0, written);
        }
      if (state.buffer_eof && state.buffer->len == 0)
        {
          if (shutdown (fd, SHUT_WR) < 0)
            {
              if (errno != EAGAIN && errno != EBADF)
                g_critical ("couldn't shutdown: %s", g_strerror (errno));
            }
          else
{'fraction_non_alphanumeric': 0.117740308401787, 'fraction_numerical': 0.008935005043954461, 'mean_word_length': 2.322163714696027, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2837135', 'n_tokens_mistral': 2491, 'n_tokens_neox': 2344, 'n_words': 671}