
/*
 * msg.c
 *
 * Written by Archie Cobbs <archie@freebsd.org>
 * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
 * See ``COPYRIGHT.whistle''
 */

#include "ppp.h"
#include "msg.h"

/*
 * DEFINITIONS
 */

/* Which pipe file descriptor is which */

  #define PIPE_READ		0
  #define PIPE_WRITE		1

  struct mpmsg
  {
    long	type;
    void	*arg;
  };
  typedef struct mpmsg	*Msg;

  struct msghandler
  {
    int		pipe[2];
    int		prio;
    void	(*func)(int type, void *arg);
    EventRef	event;
    Bund	bund;
    Link	lnk;
  };

/*
 * INTERNAL FUNCTIONS
 */

  static void	MsgEvent(int type, void *cookie);
  static void	MsgReregister(MsgHandler m);

/*
 * MsgRegister()
 */

MsgHandler
MsgRegister(void (*func)(int type, void *arg), int prio)
{
  MsgHandler	m;

  m = Malloc(MB_UTIL, sizeof(*m));
  if (pipe(m->pipe) < 0)
  {
    Log(LG_ERR, ("mpd: pipe: %s", strerror(errno)));
    DoExit(EX_ERRDEAD);
  }
  fcntl(m->pipe[PIPE_READ], F_SETFD, 1);
  fcntl(m->pipe[PIPE_WRITE], F_SETFD, 1);
  m->prio = prio;
  m->func = func;
  m->bund = bund;
  m->lnk = lnk;
  MsgReregister(m);
  return(m);
}

/*
 * MsgUnRegister()
 */

void
MsgUnRegister(MsgHandler *m)
{
  close((*m)->pipe[PIPE_WRITE]);
  close((*m)->pipe[PIPE_READ]);
  EventUnRegister(&(*m)->event);
  Freee(*m);
  *m = NULL;
}

/*
 * MsgEvent()
 */

static void
MsgEvent(int type, void *cookie)
{
  MsgHandler	const m = (MsgHandler) cookie;
  int		nread, nrode;
  struct mpmsg	msg;

  lnk = m->lnk;
  bund = m->bund;
  for (nrode = 0; nrode < sizeof(msg); nrode += nread)
  {
    if ((nread = read(m->pipe[PIPE_READ],
      (u_char *) &msg + nrode, sizeof(msg) - nrode)) < 0)
    {
      Log(LG_ERR, ("mpd: %s: read: %s", __FUNCTION__, strerror(errno)));
      DoExit(EX_ERRDEAD);
    }
    if (nread == 0)
    {
      Log(LG_ERR, ("mpd: %s: EOF", __FUNCTION__));
      DoExit(EX_ERRDEAD);
    }
  }
  (*m->func)(msg.type, msg.arg);
  MsgReregister(m);
}

/*
 * MsgSend()
 */

void
MsgSend(MsgHandler m, int type, void *arg)
{
  struct mpmsg	msg;
  int		nw, nwrote;

  if (m == NULL)
    return;
  msg.type = type;
  msg.arg = arg;
  for (nwrote = 0; nwrote < sizeof(msg); nwrote += nw)
    if ((nw = write(m->pipe[PIPE_WRITE],
      (u_char *) &msg + nwrote, sizeof(msg) - nwrote)) < 0)
    {
      Perror("MsgSend: write");
      DoExit(EX_ERRDEAD);
    }
}

/*
 * MsgReregister()
 */

static void
MsgReregister(MsgHandler m)
{
  if (EventRegister(&m->event, EVENT_READ,
    m->pipe[PIPE_READ], m->prio, MsgEvent, m) < 0)
  {
    Log(LG_ERR, ("mpd: can't register event"));
    DoExit(EX_ERRDEAD);
  }
}

/*
 * MsgName()
 */

const char *
MsgName(int msg)
{
  switch (msg)
  {
    case MSG_OPEN:
      return("OPEN");
    case MSG_CLOSE:
      return("CLOSE");
    case MSG_UP:
      return("UP");
    case MSG_DOWN:
      return("DOWN");
    default:
      return("???");
  }
}

