Exemple #1
0
void
ipmiconsole_ctx_set_errnum (ipmiconsole_ctx_t c, int errnum)
{
  int perr;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);

  /* What do we do if a mutex lock/unlock fails here?  Ignore for
   * now.
   */

  if ((perr = pthread_mutex_lock (&(c->errnum_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));

  /* If the errnum is ERR_SUCCESS, it is not required for the user
   * to retrieve it
   */
  if (c->errnum_retrieved
      || c->errnum == IPMICONSOLE_ERR_SUCCESS)
    {
      c->errnum = errnum;
      if (errnum == IPMICONSOLE_ERR_SUCCESS)
        c->errnum_retrieved = 1;
      else
        c->errnum_retrieved = 0;
    }
  else
    IPMICONSOLE_DEBUG (("could not set errnum: current = %d, desired = %d", c->errnum, errnum));

  if ((perr = pthread_mutex_unlock (&(c->errnum_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
}
int
ipmiconsole_set_closeonexec (ipmiconsole_ctx_t c, int fd)
{
  int closeonexec;

  /* User need not pass in valid context for this function */

  if ((closeonexec = fcntl (fd, F_GETFD, 0)) < 0)
    {
      IPMICONSOLE_DEBUG (("fcntl: %s", strerror (errno)));
      if (c && c->magic == IPMICONSOLE_CTX_MAGIC)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }
  closeonexec |= FD_CLOEXEC;
  if (fcntl (fd, F_SETFD, closeonexec) < 0)
    {
      IPMICONSOLE_DEBUG (("fcntl: %s", strerror (errno)));
      if (c && c->magic == IPMICONSOLE_CTX_MAGIC)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  return (0);
}
static int
_ipmiconsole_poll (struct pollfd *ufds, unsigned int nfds, int timeout)
{
  int n;
  struct timeval tv, tv_orig;
  struct timeval start, end, delta;

  assert (ufds);

  /* prep for EINTR handling */
  if (timeout >= 0)
    {
      /* poll uses timeout in milliseconds */
      tv_orig.tv_sec = (long)timeout/1000;
      tv_orig.tv_usec = (timeout % 1000) * 1000;

      if (gettimeofday(&start, NULL) < 0)
        {
          IPMICONSOLE_DEBUG (("gettimeofday: %s", strerror (errno)));
          return (-1);
        }
    }
  else
    {
      tv_orig.tv_sec = 0;
      tv_orig.tv_usec = 0;
    }

  /* repeat poll if interrupted */
  do
    {
      n = poll(ufds, nfds, timeout);

      if (n < 0 && errno != EINTR)    /* unrecov error */
        {
          IPMICONSOLE_DEBUG (("poll: %s", strerror (errno)));
          return (-1);
        }

      if (n < 0 && timeout >= 0)      /* EINTR - adjust timeout */
        {
          if (gettimeofday(&end, NULL) < 0)
            {
              IPMICONSOLE_DEBUG (("gettimeofday: %s", strerror (errno)));
              return (-1);
            }

          timersub(&end, &start, &delta);     /* delta = end-start */
          timersub(&tv_orig, &delta, &tv);    /* tv = tvsave-delta */
          timeout = (tv.tv_sec * 1000) + (tv.tv_usec/1000);
        }
    } while (n < 0);

  return n;
}
int
ipmiconsole_engine_is_setup (void)
{
  int is_setup, perr;

  if ((perr = pthread_mutex_lock (&console_engine_is_setup_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      return (-1);
    }

  is_setup = console_engine_is_setup;

  if ((perr = pthread_mutex_unlock (&console_engine_is_setup_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      return (-1);
    }

  return (is_setup);
}
int
ipmiconsole_engine_thread_count (void)
{
  int thread_count, perr;

  if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      return (-1);
    }

  if (console_engine_thread_count > INT_MAX)
    thread_count = INT_MAX;
  else
    thread_count = console_engine_thread_count;

  if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      return (-1);
    }

  return (thread_count);
}
Exemple #6
0
int
ipmiconsole_ctx_get_errnum (ipmiconsole_ctx_t c)
{
  int perr;
  int errnum;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);

  /* What do we do if a mutex lock/unlock fails here?  Ignore for
   * now.
   */

  if ((perr = pthread_mutex_lock (&(c->errnum_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));

  errnum = c->errnum;
  c->errnum_retrieved++;

  if ((perr = pthread_mutex_unlock (&(c->errnum_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  return (errnum);
}
static void *
_ipmiconsole_engine (void *arg)
{
  int perr, ctxs_count = 0;
  unsigned int index;
  unsigned int teardown_flag = 0;
  unsigned int teardown_initiated = 0;

  assert (arg);

  index = *((unsigned int *)arg);

  assert (index < IPMICONSOLE_THREAD_COUNT_MAX);

  free (arg);

  /* No need to exit on failure, probability is low we'll SIGPIPE anyways */
  if (signal (SIGPIPE, SIG_IGN) == SIG_ERR)
    IPMICONSOLE_DEBUG (("signal: %s", strerror (errno)));

  while (!teardown_flag || ctxs_count)
    {
      struct _ipmiconsole_poll_data poll_data;
      int count;
      unsigned int timeout_len;
      unsigned int i;
      int unlock_console_engine_ctxs_mutex_flag = 0;
      int spin_wait_flag = 0;
      char buf[IPMICONSOLE_PIPE_BUFLEN];

      memset (&poll_data, '\0', sizeof (struct _ipmiconsole_poll_data));

      if ((perr = pthread_mutex_lock (&console_engine_teardown_mutex)))
        {
          /* This is one of the only truly "fatal" conditions */
          IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
          teardown_flag = 1;
        }

      if (console_engine_teardown_immediate)
        {
          if ((perr = pthread_mutex_unlock (&console_engine_teardown_mutex)))
            IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
          break;
        }

      if (console_engine_teardown)
        teardown_flag = 1;

      if ((perr = pthread_mutex_unlock (&console_engine_teardown_mutex)))
        {
          /* This is one of the only truly "fatal" conditions */
          IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
          teardown_flag = 1;
        }

      /* Notes:
       *
       * We must lock the list from here till all context data and pointers
       * are retrieved.
       */

      if ((perr = pthread_mutex_lock (&console_engine_ctxs_mutex[index])))
        {
          /* This is one of the only truly "fatal" conditions */
          IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
          teardown_flag = 1;
        }

      /* Note: Set close_session_flag in the contexts before
       * ipmiconsole_process_ctxs(), so the initiation of the closing
       * down will begin now rather than the next iteration of the
       * loop.
       */
      if (teardown_flag && !teardown_initiated)
        {
          /* XXX: Umm, if this fails, we may not be able to teardown
           * cleanly.  Break out of the loop I guess.
           */
          if (list_for_each (console_engine_ctxs[index], _teardown_initiate, NULL) < 0)
            {
              IPMICONSOLE_DEBUG (("list_for_each: %s", strerror (errno)));
              break;
            }
          teardown_initiated++;
        }

      if ((ctxs_count = ipmiconsole_process_ctxs (console_engine_ctxs[index], &timeout_len)) < 0)
        goto continue_loop;

      if (!ctxs_count && teardown_flag)
        continue;

      if (!ctxs_count)
        {
          spin_wait_flag++;
          goto continue_loop;
        }
      poll_data.ctxs_len = ctxs_count;

      /* achu: I always wonder if this poll() loop could be done far
       * more elegantly and efficiently without all this crazy
       * indexing, perhaps through a callback/event mechanism.  It'd
       * probably be more efficient, since most callback/event based
       * models have min-heap like structures inside for determining
       * what things timed out. Overall though, I don't think the O(n)
       * (n being hosts/fds) processing is really that inefficient for
       * this particular application and is not worth going back and
       * changing.  By going to a callback/event mechanism, there will
       * still be some O(n) activities within the code, so I am only
       * going to create a more efficient O(n) poll loop.
       */

      /*
       * There are 3 pfds per ctx.  One for 'ipmi_fd', 'asynccomm[0]', and 'ipmiconsole_fd'.
       *
       * There is + 1 pfds for the "console_engine_ctxs_notifier".
       * This will be set up manually here, and not in _poll_setup().
       */
      if (!(poll_data.pfds = (struct pollfd *)malloc (((poll_data.ctxs_len * 3) + 1) * sizeof (struct pollfd))))
        {
          IPMICONSOLE_DEBUG (("malloc: %s", strerror (errno)));
          goto continue_loop;
        }

      if (!(poll_data.pfds_ctxs = (ipmiconsole_ctx_t *)malloc (poll_data.ctxs_len * sizeof (ipmiconsole_ctx_t))))
        {
          IPMICONSOLE_DEBUG (("malloc: %s", strerror (errno)));
          goto continue_loop;
        }

      if ((count = list_for_each (console_engine_ctxs[index], _poll_setup, &poll_data)) < 0)
        {
          IPMICONSOLE_DEBUG (("list_for_each: %s", strerror (errno)));
          goto continue_loop;
        }

      if ((perr = pthread_mutex_unlock (&console_engine_ctxs_mutex[index])))
        IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      unlock_console_engine_ctxs_mutex_flag++;

      /* Setup notifier pipe as last remaining poll data */
      poll_data.pfds[(poll_data.ctxs_len * 3)].fd = console_engine_ctxs_notifier[index][0];
      poll_data.pfds[(poll_data.ctxs_len * 3)].events = POLLIN;
      poll_data.pfds[(poll_data.ctxs_len * 3)].revents = 0;

      if (count != ctxs_count)
        {
          IPMICONSOLE_DEBUG (("list_for_each: invalid length returned: %d", count));
          goto continue_loop;
        }

      if (poll_data.pfds_index != ctxs_count)
        {
          IPMICONSOLE_DEBUG (("invalid index set on returned: %d", poll_data.pfds_index));
          goto continue_loop;
        }

      if (_ipmiconsole_poll (poll_data.pfds, (poll_data.ctxs_len * 3) + 1, timeout_len) < 0)
        {
          IPMICONSOLE_DEBUG (("poll: %s", strerror (errno)));
          goto continue_loop;
        }

      for (i = 0; i < poll_data.ctxs_len; i++)
        {
          if (poll_data.pfds[i*3].revents & POLLERR)
            {
              IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLERR"));
              /* See comments in _ipmi_recvfrom() regarding ECONNRESET/ECONNREFUSED */
              if (_ipmi_recvfrom (poll_data.pfds_ctxs[i]) < 0)
                {
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_SYSTEM_ERROR);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (!poll_data.pfds_ctxs[i]->session.close_session_flag)
            {
              if (poll_data.pfds[i*3+1].revents & POLLNVAL)
                {
                  /* This indicates the user closed the asynccomm file descriptors
                   * which is ok.
                   */
                  IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLNVAL"));
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_SUCCESS);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
              if (poll_data.pfds[i*3+2].revents & POLLHUP)
                {
                  /* This indicates the user closed the other end of
                   * the socketpair so it's ok.
                   */
                  IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLHUP"));
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_SUCCESS);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
              if (poll_data.pfds[i*3+1].revents & POLLERR)
                {
                  IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLERR"));
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_INTERNAL_ERROR);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
              if (poll_data.pfds[i*3+2].revents & POLLERR)
                {
                  IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLERR"));
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_INTERNAL_ERROR);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (poll_data.pfds[i*3].revents & POLLIN)
            {
              if (_ipmi_recvfrom (poll_data.pfds_ctxs[i]) < 0)
                {
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (poll_data.pfds[i*3].revents & POLLOUT)
            {
              if (_ipmi_sendto (poll_data.pfds_ctxs[i]) < 0)
                {
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (poll_data.pfds[i*3 + 1].revents & POLLIN)
            {
              if (_asynccomm (poll_data.pfds_ctxs[i]) < 0)
                {
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (!poll_data.pfds_ctxs[i]->session.close_session_flag)
            {
              if (poll_data.pfds[i*3+2].revents & POLLIN)
                {
                  if (_console_read (poll_data.pfds_ctxs[i]) < 0)
                    {
                      poll_data.pfds_ctxs[i]->session.close_session_flag++;
                      continue;
                    }
                }
              if (poll_data.pfds[i*3+2].revents & POLLOUT)
                {
                  if (_console_write (poll_data.pfds_ctxs[i]) < 0)
                    {
                      poll_data.pfds_ctxs[i]->session.close_session_flag++;
                      continue;
                    }
                }
            }
        }

      /* We don't care what's read, just get it off the fd */
      if (poll_data.pfds[(poll_data.ctxs_len * 3)].revents & POLLIN)
        {
          if (read (console_engine_ctxs_notifier[index][0], buf, IPMICONSOLE_PIPE_BUFLEN) < 0)
            IPMICONSOLE_DEBUG (("read: %s", strerror (errno)));
        }

    continue_loop:
      if (!unlock_console_engine_ctxs_mutex_flag)
        {
          if ((perr = pthread_mutex_unlock (&console_engine_ctxs_mutex[index])))
            {
              /* This is one of the only truly "fatal" conditions */
              IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
              teardown_flag = 1;
            }
        }
      if (spin_wait_flag)
        {
          /* No contexts stored, either because they all died or none
           * have been submitted yet.  Sleep a little bit to kill some
           * time and avoid spinning.
           */
          /* XXX: Is this portable? */
          usleep (IPMICONSOLE_SPIN_WAIT_TIME);
        }
      free (poll_data.pfds);
      free (poll_data.pfds_ctxs);
    }

  /* No way to return error, so just continue on even if there is a failure */
  if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
    IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));

  console_engine_thread_count--;

  if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  return (NULL);
}
/* Notes: One of the reason we do not create the threads in this
 * function, is that it would make it more difficult to properly
 * "cleanup" on an error.  We wouldn't know how many threads were
 * created, flags for setup completion may not be set yet, etc.
 *
 * Therefore ipmiconsole_engine_thread_create() is done outside of
 * this function and is done elsewhere.
 */
int
ipmiconsole_engine_setup (unsigned int thread_count)
{
  unsigned int i;
  int perr;

  assert (!console_engine_thread_count);
  assert (thread_count && thread_count <= IPMICONSOLE_THREAD_COUNT_MAX);

  if ((perr = pthread_mutex_lock (&console_engine_is_setup_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      errno = perr;
      return (-1);
    }

  memset (console_engine_ctxs, '\0', IPMICONSOLE_THREAD_COUNT_MAX * sizeof (List));
  memset (console_engine_ctxs_count, '\0', IPMICONSOLE_THREAD_COUNT_MAX * sizeof (unsigned int));
  memset (console_engine_ctxs_mutex, '\0', IPMICONSOLE_THREAD_COUNT_MAX * sizeof (pthread_mutex_t));
  for (i = 0; i < IPMICONSOLE_THREAD_COUNT_MAX; i++)
    {
      console_engine_ctxs_notifier[i][0] = -1;
      console_engine_ctxs_notifier[i][1] = -1;
    }
  garbage_collector_notifier[0] = -1;
  garbage_collector_notifier[1] = -1;

  if (ipmi_rmcpplus_init () < 0)
    {
      if (errno == EPERM)
        IPMICONSOLE_DEBUG (("ipmi_rmcpplus_init: incompatible crypto library"));
      else
        IPMICONSOLE_DEBUG (("ipmi_rmcpplus_init: %s", strerror (errno)));
      goto cleanup;
    }

  for (i = 0; i < IPMICONSOLE_THREAD_COUNT_MAX; i++)
    {
      if (!(console_engine_ctxs[i] = list_create ((ListDelF)ipmiconsole_ctx_connection_cleanup_session_submitted)))
        {
          IPMICONSOLE_DEBUG (("list_create: %s", strerror (errno)));
          goto cleanup;
        }
      console_engine_ctxs_count[i] = 0;
      if ((perr = pthread_mutex_init (&console_engine_ctxs_mutex[i], NULL)) != 0)
        {
          IPMICONSOLE_DEBUG (("pthread_mutex_init: %s", strerror (perr)));
          goto cleanup;
        }
    }

  /* Don't create fds for all ctxs_notifier to limit fd creation */
  console_engine_ctxs_notifier_num = thread_count;
  for (i = 0; i < console_engine_ctxs_notifier_num; i++)
    {
      if (pipe (console_engine_ctxs_notifier[i]) < 0)
        {
          IPMICONSOLE_DEBUG (("pipe: %s", strerror (errno)));
          goto cleanup;
        }

      if (ipmiconsole_set_closeonexec (NULL, console_engine_ctxs_notifier[i][0]) < 0)
        {
          IPMICONSOLE_DEBUG (("closeonexec error"));
          goto cleanup;
        }

      if (ipmiconsole_set_closeonexec (NULL, console_engine_ctxs_notifier[i][1]) < 0)
        {
          IPMICONSOLE_DEBUG (("closeonexec error"));
          goto cleanup;
        }
    }

  if (pipe (garbage_collector_notifier) < 0)
    {
      IPMICONSOLE_DEBUG (("pipe: %s", strerror (errno)));
      goto cleanup;
    }

  if (ipmiconsole_set_closeonexec (NULL, garbage_collector_notifier[0]) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  if (ipmiconsole_set_closeonexec (NULL, garbage_collector_notifier[1]) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  if (!(console_engine_ctxs_to_destroy = list_create ((ListDelF)ipmiconsole_ctx_list_cleanup)))
    {
      IPMICONSOLE_DEBUG (("list_create: %s", strerror (errno)));
      goto cleanup;
    }

  if ((dummy_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
    {
      IPMICONSOLE_DEBUG (("socket: %s", strerror (errno)));
      goto cleanup;
    }

  if (_ipmiconsole_garbage_collector_create () < 0)
    goto cleanup;

  console_engine_is_setup++;
  console_engine_teardown = 0;
  console_engine_teardown_immediate = 0;

  if ((perr = pthread_mutex_unlock (&console_engine_is_setup_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  return (0);

 cleanup:
  for (i = 0; i < IPMICONSOLE_THREAD_COUNT_MAX; i++)
    {
      if (console_engine_ctxs[i])
        {
          list_destroy (console_engine_ctxs[i]);
          pthread_mutex_destroy (&console_engine_ctxs_mutex[i]);
        }
      console_engine_ctxs[i] = NULL;
      /* ignore potential error, cleanup path */
      close (console_engine_ctxs_notifier[i][0]);
      /* ignore potential error, cleanup path */
      close (console_engine_ctxs_notifier[i][1]);
    }
  if (console_engine_ctxs_to_destroy)
    list_destroy (console_engine_ctxs_to_destroy);
  console_engine_ctxs_to_destroy = NULL;
  garbage_collector_notifier[0] = -1;
  garbage_collector_notifier[1] = -1;
  /* ignore potential error, cleanup path */
  close (dummy_fd);
  dummy_fd = -1;

  if ((perr = pthread_mutex_unlock (&console_engine_is_setup_mutex)))
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  return (-1);
}
int
ipmiconsole_engine_cleanup (int cleanup_sol_sessions)
{
  unsigned int i;
  unsigned int thread_count;
  int perr, rv = -1;

  if ((perr = pthread_mutex_lock (&console_engine_is_setup_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      return (-1);
    }

  if (!console_engine_is_setup)
    goto unlock_is_setup_mutex;

  if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      goto unlock_is_setup_mutex;
    }

  thread_count = console_engine_thread_count;

  if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      goto unlock_is_setup_mutex;
    }

  if (!thread_count)
    {
      rv = 0;
      goto engine_cleanup;
    }

  if ((perr = pthread_mutex_lock (&console_engine_teardown_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      goto engine_cleanup;
    }

  console_engine_teardown++;
  if (!cleanup_sol_sessions)
    console_engine_teardown_immediate++;

  if ((perr = pthread_mutex_unlock (&console_engine_teardown_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      goto engine_cleanup;
    }

  /* "Interrupt" the engine thread and tell it to get moving along */
  for (i = 0; i < console_engine_ctxs_notifier_num; i++)
    {
      if (write (console_engine_ctxs_notifier[i][1], "1", 1) < 0)
        IPMICONSOLE_DEBUG (("write: %s", strerror (errno)));
    }

  if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      goto engine_cleanup;
    }

  while (console_engine_thread_count)
    {
      if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
        {
          IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
          goto engine_cleanup;
        }

      /* Wait awhile then try again */
      /* XXX: Is this portable? */
      usleep (IPMICONSOLE_SPIN_WAIT_TIME);

      if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
        {
          IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
          goto engine_cleanup;
        }
    }

  if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      goto engine_cleanup;
    }

  /* "Interrupt" the garbage collector and tell it to quit */
  if (write (garbage_collector_notifier[1], "1", 1) < 0)
    IPMICONSOLE_DEBUG (("write: %s", strerror (errno)));

  if ((perr = pthread_mutex_lock (&garbage_collector_active_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      goto engine_cleanup;
    }

  while (garbage_collector_active)
    {
      if ((perr = pthread_cond_wait (&garbage_collector_active_cond,
				     &garbage_collector_active_mutex)))
	{
	  IPMICONSOLE_DEBUG (("pthread_cond_wait: %s", strerror (perr)));
	  goto engine_cleanup;
	}
    }

  if ((perr = pthread_mutex_unlock (&garbage_collector_active_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      goto engine_cleanup;
    }

 engine_cleanup:
  for (i = 0; i < IPMICONSOLE_THREAD_COUNT_MAX; i++)
    {
      if (console_engine_ctxs[i])
        list_destroy (console_engine_ctxs[i]);
      console_engine_ctxs[i] = NULL;
      console_engine_ctxs[i] = 0;
      pthread_mutex_destroy (&console_engine_ctxs_mutex[i]);
      /* ignore potential error, cleanup path */
      close (console_engine_ctxs_notifier[i][0]);
      /* ignore potential error, cleanup path */
      close (console_engine_ctxs_notifier[i][1]);
    }
  /* ignore potential error, cleanup path */
  close (garbage_collector_notifier[0]);
  /* ignore potential error, cleanup path */
  close (garbage_collector_notifier[1]);

  /* achu: The engine threads have been torn down, all the contexts
   * managed by those threads have been moved to
   * console_engine_ctxs_to_destroy, and the garbage collector has
   * been shut down.  So we don't need to lock w/ the
   * console_engine_ctxs_to_destroy_mutex.
   * 
   * This list destruction could race w/ API code b/c the user could
   * still be running around trying to use the contexts post
   * engine_teardown() (e.g. calling ipmiconsole_ctx_destroy() after
   * calling ipmiconsole_engine_teardown()).  We assume the user won't
   * do this.
   */

  list_destroy (console_engine_ctxs_to_destroy);
  console_engine_ctxs_to_destroy = NULL;

  /* ignore potential error, cleanup path */
  close (dummy_fd);
  dummy_fd = -1;

  console_engine_is_setup = 0;

  if ((perr = pthread_mutex_lock (&console_engine_teardown_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      goto unlock_is_setup_mutex;
    }

  console_engine_teardown = 0;
  console_engine_teardown_immediate = 0;

  if ((perr = pthread_mutex_unlock (&console_engine_teardown_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      goto unlock_is_setup_mutex;
    }

  rv = 0;
 unlock_is_setup_mutex:
  if ((perr = pthread_mutex_unlock (&console_engine_is_setup_mutex)))
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  return (rv);
}
int
ipmiconsole_engine_submit_ctx (ipmiconsole_ctx_t c)
{
  void *ptr;
  unsigned int i;
  int perr, ret = -1;
  unsigned int min_submitted = UINT_MAX;
  int index = 0;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);
  assert (!(c->session_submitted));
  assert (console_engine_is_setup);

  if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      return (-1);
    }

  for (i = 0; i < console_engine_thread_count; i++)
    {
      if ((perr = pthread_mutex_lock (&console_engine_ctxs_mutex[i])))
        {
          IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
          goto cleanup_thread_count;
        }

      if (console_engine_ctxs_count[i] < min_submitted)
        {
          min_submitted = console_engine_ctxs_count[i];
          index = i;
        }

      if ((perr = pthread_mutex_unlock (&console_engine_ctxs_mutex[i])))
        {
          IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
          goto cleanup_thread_count;
        }
    }

  if ((perr = pthread_mutex_lock (&console_engine_ctxs_mutex[index])))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      goto cleanup_thread_count;
    }

  if (!(ptr = list_append (console_engine_ctxs[index], c)))
    {
      /* Note: Don't do a CTX debug, this is more of a global debug */
      IPMICONSOLE_DEBUG (("list_append: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      goto cleanup_ctxs;
    }

  if (ptr != (void *)c)
    {
      IPMICONSOLE_DEBUG (("list_append: invalid pointer: ptr=%p; c=%p", ptr, c));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      goto cleanup_ctxs;
    }

  console_engine_ctxs_count[index]++;

  ret = 0;

  /* achu:
   *
   * Necessary to set this here b/c at this point in time, the context
   * is submitted, so the engine will be doing its own cleanup
   * (garbage collector, etc.).
   */
  c->session_submitted++;

  /* "Interrupt" the engine and tell it to get moving along w/ the new context */
  if (write (console_engine_ctxs_notifier[index][1], "1", 1) < 0)
    IPMICONSOLE_DEBUG (("write: %s", strerror (errno)));

 cleanup_ctxs:
  if ((perr = pthread_mutex_unlock (&console_engine_ctxs_mutex[index])))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      goto cleanup_thread_count;
    }

 cleanup_thread_count:
  if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  return (ret);
}
static int
_ipmiconsole_garbage_collector_create (void)
{
  pthread_t thread;
  pthread_attr_t attr;
  int perr, rv = -1;

  assert (!console_engine_is_setup);

  if ((perr = pthread_attr_init (&attr)))
    {
      IPMICONSOLE_DEBUG (("pthread_attr_init: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  if ((perr = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED)))
    {
      IPMICONSOLE_DEBUG (("pthread_attr_setdetachstate: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  if ((perr = pthread_create (&thread, &attr, ipmiconsole_garbage_collector, NULL)))
    {
      IPMICONSOLE_DEBUG (("pthread_create: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  /* Who cares if this fails */
  if ((perr = pthread_attr_destroy (&attr)))
    IPMICONSOLE_DEBUG (("pthread_attr_destroy: %s", strerror (perr)));

  if ((perr = pthread_mutex_lock (&garbage_collector_active_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  while (!garbage_collector_active)
    {
      if ((perr = pthread_cond_wait (&garbage_collector_active_cond,
				     &garbage_collector_active_mutex)))
	{
	  IPMICONSOLE_DEBUG (("pthread_cond_wait: %s", strerror (perr)));
	  errno = perr;
	  goto cleanup;
	}
    }

  if ((perr = pthread_mutex_unlock (&garbage_collector_active_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  rv = 0;
 cleanup:
  return (rv);
}
/* Notes: On an error, it is the responsibility of the caller to call
 * ipmiconsole_engine_cleanup() to destroy all previously created
 * threads.
 */
int
ipmiconsole_engine_thread_create (void)
{
  pthread_t thread;
  pthread_attr_t attr;
  unsigned int *index = NULL;
  int perr, rv = -1;

  assert (console_engine_is_setup);

  if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      errno = perr;
      return (-1);
    }

  assert (console_engine_thread_count < IPMICONSOLE_THREAD_COUNT_MAX);

  if ((perr = pthread_attr_init (&attr)))
    {
      IPMICONSOLE_DEBUG (("pthread_attr_init: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  if ((perr = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED)))
    {
      IPMICONSOLE_DEBUG (("pthread_attr_setdetachstate: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  if (!(index = (unsigned int *)malloc (sizeof (unsigned int))))
    {
      IPMICONSOLE_DEBUG (("malloc: %s", strerror (errno)));
      goto cleanup;
    }
  *index = console_engine_thread_count;

  if ((perr = pthread_create (&thread, &attr, _ipmiconsole_engine, index)))
    {
      IPMICONSOLE_DEBUG (("pthread_create: %s", strerror (perr)));
      errno = perr;
      goto cleanup;
    }

  /* Who cares if this fails */
  if ((perr = pthread_attr_destroy (&attr)))
    IPMICONSOLE_DEBUG (("pthread_attr_destroy: %s", strerror (perr)));

  console_engine_thread_count++;

  rv = 0;
 cleanup:

  if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      errno = perr;
      return (-1);
    }

  return (rv);
}
Exemple #13
0
static void
__ipmiconsole_ctx_connection_cleanup (ipmiconsole_ctx_t c, int session_submitted)
{
  int blocking_requested = 0;
  int status_initial = 0;
  int secure_malloc_flag;
  int perr;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);

  secure_malloc_flag = (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY) ? 1 : 0;

  /* We have to cleanup, so in general continue on even if locking fails */

  if ((perr = pthread_mutex_lock (&(c->signal.status_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));

  /* Don't change status if it's already been set before */
  if (c->signal.status != IPMICONSOLE_CTX_STATUS_SOL_ESTABLISHED)
    {
      c->signal.status = IPMICONSOLE_CTX_STATUS_SOL_ERROR;
      status_initial++;
    }

  if ((perr = pthread_mutex_unlock (&(c->signal.status_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  if ((perr = pthread_mutex_lock (&(c->blocking.blocking_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));

  if (c->blocking.blocking_submit_requested
      && !c->blocking.sol_session_established)
    {
      uint8_t tmpbyte;

      blocking_requested++;

      if (c->config.behavior_flags & IPMICONSOLE_BEHAVIOR_DEACTIVATE_ONLY
          && c->session.deactivate_only_succeeded_flag)
        tmpbyte = IPMICONSOLE_BLOCKING_NOTIFICATION_SOL_SESSION_DEACTIVATED;
      else
        tmpbyte = IPMICONSOLE_BLOCKING_NOTIFICATION_SOL_SESSION_ERROR;

      if (write (c->blocking.blocking_notification[1], &tmpbyte, 1) < 0)
        IPMICONSOLE_CTX_DEBUG (c, ("write: %s", strerror (errno)));
    }

  if ((perr = pthread_mutex_unlock (&(c->blocking.blocking_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  /* only call the callback if it's an initial SOL error and blocking
   * was not requested and the session was submitted.  We do not want
   * to call the callback if an error happened in API land and we are
   * calling in via
   * ipmiconsole_ctx_connection_cleanup_session_not_submitted().
   */
  if (status_initial
      && !blocking_requested
      && session_submitted
      && c->non_blocking.callback)
    (*(c->non_blocking.callback))(c->non_blocking.callback_arg);

  /* Under default circumstances, close only the ipmiconsole_fd so
   * that an error will be detected by the user via a EOF on a read()
   * or EPIPE on a write() when reading/writing on their file
   * descriptor.
   *
   * On error situations (i.e. ipmiconsole_engine_submit() doesn't
   * return to the user w/ success), it is the responsibility of other
   * code to call _ipmiconsole_ctx_api_managed_session_data_cleanup().
   *
   * The exception to this is when the user specifies the
   * IPMICONSOLE_ENGINE_CLOSE_FD flag.  Then we close it here
   */
  if (c->config.engine_flags & IPMICONSOLE_ENGINE_CLOSE_FD)
    {
      /* ignore potential error, cleanup path */
      if (c->connection.user_fd >= 0)
        close (c->connection.user_fd);
    }
  /* ignore potential error, cleanup path */
  if (c->connection.ipmiconsole_fd >= 0)
    close (c->connection.ipmiconsole_fd);
  if (c->connection.console_remote_console_to_bmc)
    scbuf_destroy (c->connection.console_remote_console_to_bmc, secure_malloc_flag);
  if (c->connection.console_bmc_to_remote_console)
    scbuf_destroy (c->connection.console_bmc_to_remote_console, secure_malloc_flag);
  /* ignore potential error, cleanup path */
  if (c->connection.ipmi_fd >= 0)
    close (c->connection.ipmi_fd);
  if (c->connection.ipmi_from_bmc)
    scbuf_destroy (c->connection.ipmi_from_bmc, secure_malloc_flag);
  if (c->connection.ipmi_to_bmc)
    scbuf_destroy (c->connection.ipmi_to_bmc, secure_malloc_flag);
  /* Similarly to the user_fd above, it is the responsibility of other
   * code to close asynccomm[0] and asynccomm[1], which is replicated
   * in the context.
   */
  if (c->connection.obj_rmcp_hdr_rq)
    fiid_obj_destroy (c->connection.obj_rmcp_hdr_rq);
  if (c->connection.obj_rmcp_hdr_rs)
    fiid_obj_destroy (c->connection.obj_rmcp_hdr_rs);
  if (c->connection.obj_lan_session_hdr_rq)
    fiid_obj_destroy (c->connection.obj_lan_session_hdr_rq);
  if (c->connection.obj_lan_session_hdr_rs)
    fiid_obj_destroy (c->connection.obj_lan_session_hdr_rs);
  if (c->connection.obj_lan_msg_hdr_rq)
    fiid_obj_destroy (c->connection.obj_lan_msg_hdr_rq);
  if (c->connection.obj_lan_msg_hdr_rs)
    fiid_obj_destroy (c->connection.obj_lan_msg_hdr_rs);
  if (c->connection.obj_lan_msg_trlr_rs)
    fiid_obj_destroy (c->connection.obj_lan_msg_trlr_rs);
  if (c->connection.obj_rmcpplus_session_hdr_rq)
    fiid_obj_destroy (c->connection.obj_rmcpplus_session_hdr_rq);
  if (c->connection.obj_rmcpplus_session_hdr_rs)
    fiid_obj_destroy (c->connection.obj_rmcpplus_session_hdr_rs);
  if (c->connection.obj_rmcpplus_payload_rs)
    fiid_obj_destroy (c->connection.obj_rmcpplus_payload_rs);
  if (c->connection.obj_rmcpplus_session_trlr_rq)
    fiid_obj_destroy (c->connection.obj_rmcpplus_session_trlr_rq);
  if (c->connection.obj_rmcpplus_session_trlr_rs)
    fiid_obj_destroy (c->connection.obj_rmcpplus_session_trlr_rs);
  if (c->connection.obj_authentication_capabilities_rq)
    fiid_obj_destroy (c->connection.obj_authentication_capabilities_rq);
  if (c->connection.obj_authentication_capabilities_rs)
    fiid_obj_destroy (c->connection.obj_authentication_capabilities_rs);
  if (c->connection.obj_open_session_request)
    fiid_obj_destroy (c->connection.obj_open_session_request);
  if (c->connection.obj_open_session_response)
    fiid_obj_destroy (c->connection.obj_open_session_response);
  if (c->connection.obj_rakp_message_1)
    fiid_obj_destroy (c->connection.obj_rakp_message_1);
  if (c->connection.obj_rakp_message_2)
    fiid_obj_destroy (c->connection.obj_rakp_message_2);
  if (c->connection.obj_rakp_message_3)
    fiid_obj_destroy (c->connection.obj_rakp_message_3);
  if (c->connection.obj_rakp_message_4)
    fiid_obj_destroy (c->connection.obj_rakp_message_4);
  if (c->connection.obj_set_session_privilege_level_rq)
    fiid_obj_destroy (c->connection.obj_set_session_privilege_level_rq);
  if (c->connection.obj_set_session_privilege_level_rs)
    fiid_obj_destroy (c->connection.obj_set_session_privilege_level_rs);
  if (c->connection.obj_get_channel_payload_support_rq)
    fiid_obj_destroy (c->connection.obj_get_channel_payload_support_rq);
  if (c->connection.obj_get_channel_payload_support_rs)
    fiid_obj_destroy (c->connection.obj_get_channel_payload_support_rs);
  if (c->connection.obj_get_payload_activation_status_rq)
    fiid_obj_destroy (c->connection.obj_get_payload_activation_status_rq);
  if (c->connection.obj_get_payload_activation_status_rs)
    fiid_obj_destroy (c->connection.obj_get_payload_activation_status_rs);
  if (c->connection.obj_activate_payload_rq)
    fiid_obj_destroy (c->connection.obj_activate_payload_rq);
  if (c->connection.obj_activate_payload_rs)
    fiid_obj_destroy (c->connection.obj_activate_payload_rs);
  if (c->connection.obj_sol_payload_data_rq)
    fiid_obj_destroy (c->connection.obj_sol_payload_data_rq);
  if (c->connection.obj_sol_payload_data_rs)
    fiid_obj_destroy (c->connection.obj_sol_payload_data_rs);
  if (c->connection.obj_get_channel_payload_version_rq)
    fiid_obj_destroy (c->connection.obj_get_channel_payload_version_rq);
  if (c->connection.obj_get_channel_payload_version_rs)
    fiid_obj_destroy (c->connection.obj_get_channel_payload_version_rs);
  if (c->connection.obj_deactivate_payload_rq)
    fiid_obj_destroy (c->connection.obj_deactivate_payload_rq);
  if (c->connection.obj_deactivate_payload_rs)
    fiid_obj_destroy (c->connection.obj_deactivate_payload_rs);
  if (c->connection.obj_close_session_rq)
    fiid_obj_destroy (c->connection.obj_close_session_rq);
  if (c->connection.obj_close_session_rs)
    fiid_obj_destroy (c->connection.obj_close_session_rs);

  _ipmiconsole_ctx_connection_init (c);

  /* If the session was never submitted (i.e. error in API land), don't
   * move this around.
   */

  /* achu: See note in ipmiconsole_defs.h about the
   * c->session_submitted flag.  That flag is only used in API land
   * for the user to know if a session was submitted or not.  The
   * session_submitted flag passed into this function is the "real"
   * one that is known by the engine, and is not dependent on any race
   * conditions with the API level.
   */

  if (!session_submitted)
    return;

  /* Be careful, if the user requested to destroy the context, we can
   * destroy it here.  But if we destroy it, there is no mutex to
   * unlock.
   */

  /* Note: the code in __ipmiconsole_ctx_connection_cleanup() and
   * ipmiconsole_garbage_collector() may look like it may race and
   * could deadlock.  (ABBA and BAAB deadlock situation).  However,
   * the context mutex c->signal.destroyed_mutex is accessed in
   * __ipmiconsole_ctx_connection_cleanup() when trying to add this item
   * to the console_engine_ctxs_to_destroy list.  It is accessed in
   * ipmiconsole_garbage_collector() only on the items already in the
   * console_engine_ctxs_to_destroy list.  So the
   * c->signal.destroyed_mutex can never be raced against in these two
   * functions.
   */
  if ((perr = pthread_mutex_lock (&(c->signal.destroyed_mutex))) != 0)
    IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));

  if (c->signal.user_has_destroyed)
    {
      ipmiconsole_ctx_debug_cleanup (c);
      ipmiconsole_ctx_signal_cleanup (c);
      ipmiconsole_ctx_blocking_cleanup (c);
      ipmiconsole_ctx_cleanup (c);
    }
  else
    {
      if (!c->signal.moved_to_destroyed)
        {
          void *ptr;

          c->signal.moved_to_destroyed++;

          /* I suppose if we fail here, we mem-leak?? Log for now ... */

          if ((perr = pthread_mutex_lock (&(console_engine_ctxs_to_destroy_mutex))) != 0)
            IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));

          if (!(ptr = list_append (console_engine_ctxs_to_destroy, c)))
            IPMICONSOLE_DEBUG (("list_append: %s", strerror (errno)));

          if (ptr != (void *)c)
            IPMICONSOLE_DEBUG (("list_append: invalid pointer: ptr=%p; c=%p", ptr, c));

          if ((perr = pthread_mutex_unlock (&(console_engine_ctxs_to_destroy_mutex))) != 0)
            IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
        }

      if ((perr = pthread_mutex_unlock (&(c->signal.destroyed_mutex))) != 0)
        IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
    }
}
Exemple #14
0
int
ipmiconsole_ctx_connection_setup (ipmiconsole_ctx_t c)
{
  struct sockaddr_in srcaddr;
  int sv[2];
  int secure_malloc_flag;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);
  assert (!(c->session_submitted));

  _ipmiconsole_ctx_connection_init (c);

  /* File Descriptor User Interface */

  if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
    {
      IPMICONSOLE_DEBUG (("socketpair: %s", strerror (errno)));
      if (errno == EMFILE)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES);
      else
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      goto cleanup;
    }
  c->connection.user_fd = sv[0];
  c->connection.ipmiconsole_fd = sv[1];

  if (ipmiconsole_set_closeonexec (c, c->connection.user_fd) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }
  if (ipmiconsole_set_closeonexec (c, c->connection.ipmiconsole_fd) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  /* Copy for API level */
  c->fds.user_fd = c->connection.user_fd;

  secure_malloc_flag = (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY) ? 1 : 0;

  if (!(c->connection.console_remote_console_to_bmc = scbuf_create (CONSOLE_REMOTE_CONSOLE_TO_BMC_BUF_MIN, CONSOLE_REMOTE_CONSOLE_TO_BMC_BUF_MAX, secure_malloc_flag)))
    {
      IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  if (!(c->connection.console_bmc_to_remote_console = scbuf_create (CONSOLE_BMC_TO_REMOTE_CONSOLE_BUF_MIN, CONSOLE_BMC_TO_REMOTE_CONSOLE_BUF_MAX, secure_malloc_flag)))
    {
      IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  /* Connection Data */

  if ((c->connection.ipmi_fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
    {
      IPMICONSOLE_DEBUG (("socket: %s", strerror (errno)));
      if (errno == EMFILE)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES);
      else
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      goto cleanup;
    }

  if (ipmiconsole_set_closeonexec (c, c->connection.ipmi_fd) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  memset (&srcaddr, '\0', sizeof (struct sockaddr_in));
  srcaddr.sin_family = AF_INET;
  srcaddr.sin_port = htons (0);
  srcaddr.sin_addr.s_addr = htonl (INADDR_ANY);

  if (bind (c->connection.ipmi_fd, (struct sockaddr *)&srcaddr, sizeof (struct sockaddr_in)) < 0)
    {
      IPMICONSOLE_DEBUG (("bind: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      goto cleanup;
    }

  if (!(c->connection.ipmi_from_bmc = scbuf_create (IPMI_FROM_BMC_BUF_MIN, IPMI_FROM_BMC_BUF_MAX, secure_malloc_flag)))
    {
      IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  if (!(c->connection.ipmi_to_bmc = scbuf_create (IPMI_TO_BMC_BUF_MIN, IPMI_TO_BMC_BUF_MAX, secure_malloc_flag)))
    {
      IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  /* Pipe for non-fd communication */
  if (pipe (c->connection.asynccomm) < 0)
    {
      IPMICONSOLE_DEBUG (("pipe: %s", strerror (errno)));
      if (errno == EMFILE)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES);
      else
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      goto cleanup;
    }

  if (ipmiconsole_set_closeonexec (c, c->connection.asynccomm[0]) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  if (ipmiconsole_set_closeonexec (c, c->connection.asynccomm[1]) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  /* Copy for API level */
  c->fds.asynccomm[0] = c->connection.asynccomm[0];
  c->fds.asynccomm[1] = c->connection.asynccomm[1];

  /* Fiid Objects */

  if (!(c->connection.obj_rmcp_hdr_rq = fiid_obj_create (tmpl_rmcp_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcp_hdr_rs = fiid_obj_create (tmpl_rmcp_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_session_hdr_rq = fiid_obj_create (tmpl_lan_session_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_session_hdr_rs = fiid_obj_create (tmpl_lan_session_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_msg_hdr_rq = fiid_obj_create (tmpl_lan_msg_hdr_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_msg_hdr_rs = fiid_obj_create (tmpl_lan_msg_hdr_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_msg_trlr_rs = fiid_obj_create (tmpl_lan_msg_trlr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_session_hdr_rq = fiid_obj_create (tmpl_rmcpplus_session_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_session_hdr_rs = fiid_obj_create (tmpl_rmcpplus_session_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_payload_rs = fiid_obj_create (tmpl_rmcpplus_payload)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_session_trlr_rq = fiid_obj_create (tmpl_rmcpplus_session_trlr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_session_trlr_rs = fiid_obj_create (tmpl_rmcpplus_session_trlr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_authentication_capabilities_rq = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_authentication_capabilities_rs = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_open_session_request = fiid_obj_create (tmpl_rmcpplus_open_session_request)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_open_session_response = fiid_obj_create (tmpl_rmcpplus_open_session_response)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rakp_message_1 = fiid_obj_create (tmpl_rmcpplus_rakp_message_1)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rakp_message_2 = fiid_obj_create (tmpl_rmcpplus_rakp_message_2)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rakp_message_3 = fiid_obj_create (tmpl_rmcpplus_rakp_message_3)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rakp_message_4 = fiid_obj_create (tmpl_rmcpplus_rakp_message_4)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_set_session_privilege_level_rq = fiid_obj_create (tmpl_cmd_set_session_privilege_level_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_set_session_privilege_level_rs = fiid_obj_create (tmpl_cmd_set_session_privilege_level_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_channel_payload_support_rq = fiid_obj_create (tmpl_cmd_get_channel_payload_support_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_channel_payload_support_rs = fiid_obj_create (tmpl_cmd_get_channel_payload_support_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_payload_activation_status_rq = fiid_obj_create (tmpl_cmd_get_payload_activation_status_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_payload_activation_status_rs = fiid_obj_create (tmpl_cmd_get_payload_activation_status_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_activate_payload_rq = fiid_obj_create (tmpl_cmd_activate_payload_sol_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_activate_payload_rs = fiid_obj_create (tmpl_cmd_activate_payload_sol_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_sol_payload_data_rq = fiid_obj_create (tmpl_sol_payload_data_remote_console_to_bmc)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_sol_payload_data_rs = fiid_obj_create (tmpl_sol_payload_data_bmc_to_remote_console)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_channel_payload_version_rq = fiid_obj_create (tmpl_cmd_get_channel_payload_version_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_channel_payload_version_rs = fiid_obj_create (tmpl_cmd_get_channel_payload_version_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_deactivate_payload_rq = fiid_obj_create (tmpl_cmd_deactivate_payload_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_deactivate_payload_rs = fiid_obj_create (tmpl_cmd_deactivate_payload_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_close_session_rq = fiid_obj_create (tmpl_cmd_close_session_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_close_session_rs = fiid_obj_create (tmpl_cmd_close_session_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  return (0);

 cleanup:
  /* Previously called here, but this is now supposed to be handled in API land */
  /* ipmiconsole_ctx_connection_cleanup(c) */
  /* _ipmiconsole_ctx_fds_cleanup(c); */
  /* _ipmiconsole_ctx_fds_setup(c); */
  return (-1);
}
Exemple #15
0
int
ipmiconsole_ctx_config_setup (ipmiconsole_ctx_t c,
                              const char *hostname,
			      uint16_t port,
                              struct ipmiconsole_ipmi_config *ipmi_config,
                              struct ipmiconsole_protocol_config *protocol_config,
                              struct ipmiconsole_engine_config *engine_config)
{
  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);
  assert (hostname);
  assert (port);

  strcpy (c->config.hostname, hostname);

  c->config.port = port;

  if (ipmi_config->username)
    strcpy (c->config.username, ipmi_config->username);
  else
    strcpy (c->config.username, default_config.username);

  if (ipmi_config->password)
    strcpy (c->config.password, ipmi_config->password);
  else
    strcpy (c->config.password, default_config.password);

  /* k_g may contain nulls */
  /* don't load defaults if k_g is not NULL */
  if (ipmi_config->k_g)
    {
      if (ipmi_config->k_g_len)
	{
	  memcpy (c->config.k_g, ipmi_config->k_g, ipmi_config->k_g_len);
	  c->config.k_g_len = ipmi_config->k_g_len;
	}
      else
	{
	  memset (c->config.k_g, '\0', IPMI_MAX_K_G_LENGTH + 1);
	  c->config.k_g_len = 0;
	}
    }
  else
    {
      memcpy (c->config.k_g, default_config.k_g, default_config.k_g_len);
      c->config.k_g_len = default_config.k_g_len;
    }

  if (c->config.k_g_len)
    {
      unsigned int i;
      int all_zeroes = 1;

      /* Special case, check to make sure user didn't input zero as a
       * k_g key.
       */
      for (i = 0; i < IPMI_MAX_K_G_LENGTH; i++)
        {
          if (c->config.k_g[i] != 0)
            {
              all_zeroes = 0;
              break;
            }
        }
      
      if (all_zeroes)
        c->config.k_g_len = 0;
    }

  if (ipmi_config->privilege_level >= 0)
    {
      if (ipmi_config->privilege_level == IPMICONSOLE_PRIVILEGE_USER)
        c->config.privilege_level = IPMI_PRIVILEGE_LEVEL_USER;
      else if (ipmi_config->privilege_level == IPMICONSOLE_PRIVILEGE_OPERATOR)
        c->config.privilege_level = IPMI_PRIVILEGE_LEVEL_OPERATOR;
      else
        c->config.privilege_level = IPMI_PRIVILEGE_LEVEL_ADMIN;
    }
  else
    c->config.privilege_level = default_config.privilege_level;

  if (ipmi_config->cipher_suite_id >= IPMI_CIPHER_SUITE_ID_MIN)
    c->config.cipher_suite_id = ipmi_config->cipher_suite_id;
  else
    c->config.cipher_suite_id = default_config.cipher_suite_id;

  if (ipmi_config->workaround_flags != IPMICONSOLE_WORKAROUND_DEFAULT)
    c->config.workaround_flags = ipmi_config->workaround_flags;
  else
    c->config.workaround_flags = default_config.workaround_flags;

  if (protocol_config->session_timeout_len > 0)
    c->config.session_timeout_len = protocol_config->session_timeout_len;
  else
    c->config.session_timeout_len = default_config.session_timeout_len;

  if (protocol_config->retransmission_timeout_len > 0)
    c->config.retransmission_timeout_len = protocol_config->retransmission_timeout_len;
  else
    c->config.retransmission_timeout_len = default_config.retransmission_timeout_len;

  if (protocol_config->retransmission_backoff_count > 0)
    c->config.retransmission_backoff_count = protocol_config->retransmission_backoff_count;
  else
    c->config.retransmission_backoff_count = default_config.retransmission_backoff_count;

  if (protocol_config->keepalive_timeout_len > 0)
    c->config.keepalive_timeout_len = protocol_config->keepalive_timeout_len;
  else
    c->config.keepalive_timeout_len = default_config.keepalive_timeout_len;

  if (protocol_config->retransmission_keepalive_timeout_len > 0)
    c->config.retransmission_keepalive_timeout_len = protocol_config->retransmission_keepalive_timeout_len;
  else
    c->config.retransmission_keepalive_timeout_len = default_config.retransmission_keepalive_timeout_len;

  if (protocol_config->acceptable_packet_errors_count > 0)
    c->config.acceptable_packet_errors_count = protocol_config->acceptable_packet_errors_count;
  else
    c->config.acceptable_packet_errors_count = default_config.acceptable_packet_errors_count;

  if (protocol_config->maximum_retransmission_count > 0)
    c->config.maximum_retransmission_count = protocol_config->maximum_retransmission_count;
  else
    c->config.maximum_retransmission_count = default_config.maximum_retransmission_count;

  if (engine_config->engine_flags != IPMICONSOLE_ENGINE_DEFAULT)
    c->config.engine_flags = engine_config->engine_flags;
  else
    c->config.engine_flags = default_config.engine_flags;

  if (engine_config->behavior_flags != IPMICONSOLE_BEHAVIOR_DEFAULT)
    c->config.behavior_flags = engine_config->behavior_flags;
  else
    c->config.behavior_flags = default_config.behavior_flags;
  
  if (engine_config->debug_flags != IPMICONSOLE_DEBUG_DEFAULT)
    c->config.debug_flags = engine_config->debug_flags;
  else
    c->config.debug_flags = default_config.debug_flags;

  c->config.sol_payload_instance = default_config.sol_payload_instance;

  /* Data based on Configuration Parameters */

  if (ipmi_cipher_suite_id_to_algorithms (c->config.cipher_suite_id,
                                          &(c->config.authentication_algorithm),
                                          &(c->config.integrity_algorithm),
                                          &(c->config.confidentiality_algorithm)) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_cipher_suite_id_to_algorithms: %s", strerror (errno)));
      return (-1);
    }

  /* Retransmission timeout cannot be larger than the session timeout */
  if (c->config.retransmission_timeout_len > c->config.session_timeout_len)
    {
      IPMICONSOLE_DEBUG (("retransmission_timeout_len (%u) > session_timeout_len (%u)",
                          c->config.retransmission_timeout_len,
                          c->config.session_timeout_len));
      errno = EINVAL;
      return (-1);
    }

  /* Keepalive timeout cannot be larger than the session timeout */
  if (c->config.keepalive_timeout_len > c->config.session_timeout_len)
    {
      IPMICONSOLE_DEBUG (("keepalive_timeout_len (%u) > session_timeout_len (%u)",
                          c->config.keepalive_timeout_len,
                          c->config.session_timeout_len));
      errno = EINVAL;
      return (-1);
    }

  /* Retransmission timeout cannot be larger than the keepalive timeout */
  if (c->config.retransmission_timeout_len > c->config.keepalive_timeout_len)
    {
      IPMICONSOLE_DEBUG (("retransmission_timeout_len (%u) > keepalive_timeout_len (%u)",
                          c->config.retransmission_timeout_len,
                          c->config.keepalive_timeout_len));
      errno = EINVAL;
      return (-1);
    }

  /* Retransmission keepalive timeout cannot be larger than the keepalive timeout */
  if (c->config.retransmission_keepalive_timeout_len > c->config.keepalive_timeout_len)
    {
      IPMICONSOLE_DEBUG (("retransmission_keepalive_timeout_len (%u) > keepalive_timeout_len (%u)",
                          c->config.retransmission_keepalive_timeout_len,
                          c->config.keepalive_timeout_len));
      errno = EINVAL;
      return (-1);
    }

  return (0);
}
Exemple #16
0
int
ipmiconsole_ctx_session_setup (ipmiconsole_ctx_t c)
{
  struct hostent hent;
  int h_errnop;
  char buf[GETHOSTBYNAME_AUX_BUFLEN];
#if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
  struct hostent *hptr;
#elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
#else /* !HAVE_FUNC_GETHOSTBYNAME_R */
  struct hostent *hptr;
#endif /* !HAVE_FUNC_GETHOSTBYNAME_R */

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);

  c->session.console_port = c->config.port;

  memset (&(c->session.addr), '\0', sizeof (struct sockaddr_in));
  c->session.addr.sin_family = AF_INET;
  c->session.addr.sin_port = htons (c->session.console_port);

  timeval_clear (&(c->session.last_ipmi_packet_sent));

  /* Note:
   *
   * Initial last_ipmi_packet_received and last_sol_packet_received to
   * current time, so appropriate timeouts can be calculated in the
   * beginning if necessary.
   */

  if (gettimeofday (&(c->session.last_ipmi_packet_received), NULL) < 0)
    {
      IPMICONSOLE_DEBUG (("gettimeofday: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  timeval_clear (&(c->session.last_keepalive_packet_sent));

  if (gettimeofday (&(c->session.last_sol_packet_received), NULL) < 0)
    {
      IPMICONSOLE_DEBUG (("gettimeofday: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  memset (&hent, '\0', sizeof (struct hostent));
#if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
  if (gethostbyname_r (c->config.hostname,
                       &hent,
                       buf,
                       GETHOSTBYNAME_AUX_BUFLEN,
                       &hptr,
                       &h_errnop))
#elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
  /* Jan Forch - Solaris gethostbyname_r returns ptr, not integer */
  if (!gethostbyname_r (c->config.hostname,
                        &hent,
                        buf,
                        GETHOSTBYNAME_AUX_BUFLEN,
                        &h_errnop))
#else /* !HAVE_FUNC_GETHOSTBYNAME_R */
  if (freeipmi_gethostbyname_r (c->config.hostname,
                                &hent,
                                buf,
                                GETHOSTBYNAME_AUX_BUFLEN,
                                &hptr,
                                &h_errnop))
#endif /* !HAVE_FUNC_GETHOSTBYNAME_R */
    {
      if (h_errnop == HOST_NOT_FOUND
          || h_errnop == NO_ADDRESS
          || h_errnop == NO_DATA)
        {
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_HOSTNAME_INVALID);
          return (-1);
        }
#if HAVE_HSTRERROR
      IPMICONSOLE_DEBUG (("gethostbyname_r: %s", hstrerror (h_errnop)));
#else /* !HAVE_HSTRERROR */
      IPMICONSOLE_DEBUG (("gethostbyname_r: h_errno = %d", h_errnop));
#endif /* !HAVE_HSTRERROR */
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

#if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
  if (!hptr)
    {
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_HOSTNAME_INVALID);
      return (-1);
    }
#elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
#else /* !HAVE_FUNC_GETHOSTBYNAME_R */
  if (!hptr)
    {
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_HOSTNAME_INVALID);
      return (-1);
    }
#endif /* !HAVE_FUNC_GETHOSTBYNAME_R */

  c->session.addr.sin_addr = *((struct in_addr *)hent.h_addr);

  c->session.protocol_state = IPMICONSOLE_PROTOCOL_STATE_START;
  c->session.close_session_flag = 0;
  c->session.try_new_port_flag = 0;
  c->session.deactivate_payload_instances = 0;
  c->session.deactivate_payload_instances_and_try_again_flag = 0;
  c->session.close_timeout_flag = 0;
  c->session.deactivate_only_succeeded_flag = 0;

  c->session.retransmission_count = 0;
  c->session.errors_count = 0;
  c->session.session_sequence_number_errors_count = 0;
  c->session.activate_payloads_count = 0;
  c->session.deactivate_active_payloads_count = 0;

  if (ipmi_check_session_sequence_number_2_0_init (&(c->session.highest_received_sequence_number),
                                                   &(c->session.previously_received_list)) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_check_session_sequence_number_2_0_init: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (ipmi_get_random (&(c->session.message_tag),
                       sizeof (c->session.message_tag)) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_get_random: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }
  if (ipmi_get_random (&(c->session.requester_sequence_number),
                       sizeof (c->session.requester_sequence_number)) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_get_random: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }
  c->session.requester_sequence_number %= (IPMI_LAN_REQUESTER_SEQUENCE_NUMBER_MAX + 1);

  c->session.session_sequence_number = 0; /* 0, so initial increment puts it at 1 */
  c->session.name_only_lookup = IPMI_NAME_ONLY_LOOKUP;

  /* In IPMI 2.0, session_ids of 0 are special */
  do
    {
      if (ipmi_get_random (&(c->session.remote_console_session_id),
                           sizeof (c->session.remote_console_session_id)) < 0)
        {
          IPMICONSOLE_DEBUG (("ipmi_get_random: %s", strerror (errno)));
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
          return (-1);
        }
    } while (!c->session.remote_console_session_id);

  if (ipmi_get_random (c->session.remote_console_random_number,
                       IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_get_random: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  /* Keys and ptrs will be calculated during session setup.  We just
   * memet/clear here.
   */
  memset (c->session.sik_key, '\0', IPMI_MAX_SIK_KEY_LENGTH);
  c->session.sik_key_ptr = c->session.sik_key;
  c->session.sik_key_len = IPMI_MAX_SIK_KEY_LENGTH;
  memset (c->session.integrity_key, '\0', IPMI_MAX_INTEGRITY_KEY_LENGTH);
  c->session.integrity_key_ptr = c->session.integrity_key;
  c->session.integrity_key_len = IPMI_MAX_INTEGRITY_KEY_LENGTH;
  memset (c->session.confidentiality_key, '\0', IPMI_MAX_CONFIDENTIALITY_KEY_LENGTH);
  c->session.confidentiality_key_ptr = c->session.confidentiality_key;
  c->session.confidentiality_key_len = IPMI_MAX_CONFIDENTIALITY_KEY_LENGTH;

  /* Following 3 will be calculated during session setup.  We only
   * memset/clear it here
   */
  c->session.sol_instance_capacity = 0;
  memset (c->session.sol_instances_activated, '\0', IPMI_INSTANCES_ACTIVATED_LENGTH);
  c->session.sol_instances_activated_count = 0;
  /* this is used just to index the number of instances deactivated */
  c->session.sol_instances_deactivated_count = 0;

  /* Calculated during the session setup. */
  c->session.max_sol_character_send_size = 0;

  /* Serial Break Maintenance */
  c->session.break_requested = 0;
  c->session.console_remote_console_to_bmc_bytes_before_break = 0;

  /* SOL Input (remote console to BMC) */
  c->session.sol_input_waiting_for_ack = 0;
  c->session.sol_input_waiting_for_break_ack = 0;
  timeval_clear (&(c->session.last_sol_input_packet_sent));
  c->session.sol_input_packet_sequence_number = 0; /* 0, so initial increment puts it at 1 */
  memset (c->session.sol_input_character_data, '\0', IPMICONSOLE_MAX_CHARACTER_DATA+1);
  c->session.sol_input_character_data_len = 0;

  /* SOL Output (BMC to remote console) */
  c->session.last_sol_output_packet_sequence_number = 0;
  c->session.last_sol_output_accepted_character_count = 0;

  return (0);
}