Logo Search packages:      
Sourcecode: yiff version File versions  Download package

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
extern int h_errno;           /* For netdb.h */
#include <time.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <ctype.h>

#define _USE_BSD
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/wait.h>

#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>          /* For inet_ntoa() */
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "../include/shm.h"
#include "../include/strexp.h"
#include "../include/string.h"
#include "../include/prochandle.h"

#include "../include/Y2/Y.h"
#include "../include/Y2/Ylib.h"
#include "../include/Y2/Yclientnet.h"


static int YIFF_CONNECT_TO(const char *address, int port);
static void YIFF_COPY_EVENTS(YEvent *tar, YEvent *src);
static void YIFF_FREE_CON(YConnection *con);


YConnection *YOpenConnection(
      const char *start_arg,
      const char *con_arg
);

int YSetAudioModeValues(
      YConnection *con,
      int sample_size,
      int channels,
      int sample_rate,
      int direction,
      int allow_fragmenting,
      int num_fragments,
      int fragment_size /* In bytes. */
);
int YChangeAudioModePreset(YConnection *con, const char *name);
YAudioModeValuesStruct **YGetAudioModes(YConnection *con, int *count);
void YFreeAudioModesList(YAudioModeValuesStruct **list, int count);
Boolean YMatchAudioModeValues(
      YConnection *con,
      YAudioModeValuesStruct *buf,
      int sample_rate,
      int sample_size,
      int channels,
      int direction
);

int YGetServerStats(YConnection *con, YEventServerStats *buf);

long YCalculateCycle(
      YConnection *con,
      int sample_rate, int channels,
      int sample_size, int fragment_size
);
int YSetCycle(YConnection *con, long us);
void YSyncAll(YConnection *con, Boolean block);

int YGetAudioStats(YConnection *con, YEventAudioStats *buf);

int YAddHost(YConnection *con, YIPUnion *ip);
int YRemoveHost(YConnection *con, YIPUnion *ip);

int YSetMixerChannel(
      YConnection *con,
      int mixer_channel_code,
      Coefficient value1, Coefficient value2
);
int YSetMixerChannelQuad(
      YConnection *con,
      int mixer_channel_code,
      Coefficient value1, Coefficient value2,
      Coefficient value3, Coefficient value4
);
int YGetMixerChannel(
      YConnection *con,
      int mixer_channel_code,
      Coefficient *value1, Coefficient *value2
);
int YGetMixerChannelQuad(
      YConnection *con,
      int mixer_channel_code,
      Coefficient *value1, Coefficient *value2,
      Coefficient *value3, Coefficient *value4
);

YID YStartPlaySoundObjectSimple(YConnection *con, const char *path);
YID YStartPlaySoundObject(
      YConnection *con,
      const char *path,
      YEventSoundPlay *value
);
int YGetSoundObjectAttributes(
      YConnection *con,
      const char *path,
      YEventSoundObjectAttributes *buf
);
void YSetPlaySoundObjectValues(
      YConnection *con, YID yid, YEventSoundPlay *value
);
int YGetPlaySoundObjectValues(
      YConnection *con, YID yid, YEventSoundPlay *value
);
void YDestroyPlaySoundObject(YConnection *con, YID yid);

int YSendClientMessage(
      YConnection *con,
      Boolean notify_self,
      int format,
      int type,
      const char *message,
      int length
);

void *YSHMOpenSound(YConnection *con, int *length, int *id);
void YSHMCloseSound(YConnection *con, void *ptr);

int YPlayAudioCDTrack(YConnection *con, int track_number);
int YStopAudioCD(YConnection *con);
int YEjectAudioCD(YConnection *con);

YAudioCDTrackStruct **YGetAudioCDTracks(YConnection *con, int *count);
void YFreeAudioCDTracksList(YAudioCDTrackStruct **list, int count);

void YCloseConnection(YConnection *con, Boolean no_shutdown);
void YShutdownServer(YConnection *con);

int YGetNextEvent(YConnection *con, YEvent *event, Boolean block);
void YPutBackEvent(YConnection *con, YEvent *event);


/* Checks if c is a white space. */
#ifndef ISBLANK
# define ISBLANK(c)     (((c) == ' ') || ((c) == '\t'))
#endif

/*
 *    Connect retries:
 */
#define YIFF_CONNECT_RETRIES  5

/*
 *    Default connection argument:
 */
#define DEF_CONNECT_ARG       "127.0.0.1:9433"

#define DEF_PORT        9433


#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define ABSOLUTE(x)     (((x) < 0) ? ((x) * -1) : (x))


/*
 *    Number of times to retry fetching events for responses in
 *    functions that need to recieve data from server.
 *
 *    Retries count as blocked event fetches but with the wrong event
 *    received.
 */
#define DEF_EVENT_FETCH_RETRIES           30


/* From yclientnet.c */
extern void YSetEventToBeDisconnect(YEvent *event);


/*
 *    Returns socket fd or -1 on error.
 */
static int YIFF_CONNECT_TO(const char *address, int port)
{
      int s;
      struct hostent *host;         /* Host pointer. */
      struct sockaddr_in haddr;


      if(address == NULL)
          return(-1);


      /* Get host address data. */
      host = gethostbyname(address);
      if(host == NULL)
          return(-1);

      /* Get a socket. */
      s = socket(AF_INET, SOCK_STREAM, 0);
      if(s < 0)
          return(-1);

      haddr.sin_family = AF_INET;         /* In hbo. */   
      haddr.sin_port = htons(port);       /* In nbo. */
      haddr.sin_addr = *((struct in_addr *)host->h_addr);
      memset(&haddr.sin_zero, 0, 8);      /* Zero the rest of struct. */

      /* Connect. */
      if(
          connect(
            s,
            (struct sockaddr *)&haddr,
            sizeof(struct sockaddr)
          ) == -1
      )
          return(-1);

      /* Set socket to non-blocking. */
/*
      fcntl(s, F_SETFL, O_NONBLOCK);
 */

      return(s);
}


/*
 *    Coppies the information from YEvent src to tar.
 *
 *    Only the information pertainant to what type of
 *    event src is will be coppied.
 */
static void YIFF_COPY_EVENTS(YEvent *tar, YEvent *src)
{
      if((tar == NULL) || (src == NULL) || (tar == src))
          return;
      else
          memcpy(tar, src, sizeof(YEvent));
}

/*
 *    Deallocates connection structure and its resources.
 *
 *    Warning, does NOT close the connection!
 */
static void YIFF_FREE_CON(YConnection *con)
{
      if(con == NULL)
          return;

      free(con->queued_event);
      free(con->buf);
      free(con);
}

/*
 *    Attempts to connect to the Y server at the address and port
 *    specified by con_arg.
 *
 *    con_arg is a null terminated string of the format
 *    "<address>:<port>", ie "127.0.0.1:9433".
 *
 *    If the connect failed and start_arg is not NULL, then
 *    start_arg will be executed as the command to start the
 *    server.  After which a connect attempt will be made again.
 *
 *    Returns a pointer to a YConnection structure or NULL on
 *    error.  To disconnect and deallocate the YConnection structure,
 *    pass it to YIFFDisconnect().
 */
YConnection *YOpenConnection(const char *start_arg, const char *con_arg)
{
      int fd;
      char addr[1024];
      int port;

      int retry_count;
      int total_retries = YIFF_CONNECT_RETRIES;
      int yiff_we_started_server = 0;

      char *strptr;
      YConnection *con;



      /* Is the connection argument string NULL? */
      if(con_arg == NULL)
      {
          /* Look for the "RECORDER" enviroment variable. */
          strptr = getenv("RECORDER");
          if(strptr == NULL)
          {
            /* "RECORDER" enviroment variable not set, then all
             * else use default connect argument.
             */
            con_arg = DEF_CONNECT_ARG;
          }
          else
          {
            con_arg = strptr;
          }
      }

      /* Parse address from connect string. */
      strncpy(addr, con_arg, 1024);
      addr[1024 - 1] = '\0';

      strptr = strchr(addr, ':');
      if(strptr != NULL)
      {
          /* Null terminate address string. */
          (*strptr) = '\0';

          /* Increment strptr to get port number. */
          strptr++;
          while(ISBLANK(*strptr))
            strptr++;
          /* Get port number. */
          port = atoi(strptr);
      }
      else
      {
          /* Set default port number. */
          port = DEF_PORT;
      }

      /* Address and port number should be fetched or atleast contain
       * default values.
       */


      /* Attempt to connect to Y server (initial try). */
      fd = YIFF_CONNECT_TO(addr, port);
      if(fd < 0)
      {
          /* Connect failed, implying that the Y server may not be
           * running. So run the server if and only if the start
           * argument start_arg is not NULL.
           */
          if(start_arg == NULL)
          {
            /* Start argument was NULL and we were unable to connect
             * to the Y server on the first try, so give up.
             */
            return(NULL);
          }
          else
          {
            /* Run the Y server. */
            Exec(start_arg);
          }

          /* Try connecting to Y server (this is the second try),
           * keep trying for a total of total_retries times.
           */
          for(retry_count = 0; retry_count < total_retries; retry_count++)
          {
              fd = YIFF_CONNECT_TO(addr, port);
            if(fd > -1)
              {
                /* Y server was probably restarted because we are
                 * able to connect. Mark that we (this process)
                 * started the Y server.
                 */
                yiff_we_started_server = 1;
                break;
            }

            /* Pause for one second in between tries. */
            sleep(1);
          }

          /* Were we able to connect after trying to restart the Y
           * server?
           */
          if(fd < 0)
          {
            /* Could not establish connection after trying to restart
             * the Y server.
             */
            return(NULL);
          }
      }

      /* Connection to Y server has been made. If this process
       * started the Y server then yiff_we_started_server will
       * be set to 1.
       */


      /* Allocate a new YConnection structure. */
      con = (YConnection *)calloc(1, sizeof(YConnection));
      if(con == NULL)
      {
          close(fd);
          return(NULL);
      }

      /* Set up connection values. */
      con->fd = fd;
      con->we_started_server = yiff_we_started_server;
      con->prev_generated_yid = YIDNULL;

      /* Reset queued events array. */
      con->total_queued_events = 0;
      con->queued_event = NULL;

      /* Allocate recieve buffer. */
      con->buf_len = YNetRecvBufLen;
      con->buf_cont = 0;
      con->buf = (u_int8_t *)calloc(
          con->buf_len,
          sizeof(u_int8_t)
      );
      if(con->buf == NULL)
          con->buf_len = 0;

      return(con);
}

/*
 *    Changes the Y server's Audio values.
 *
 *    Note that not all combinations ov values may work, since the
 *    Y server may not support certain combinations of values.  It is
 *    recommended that you use YChangeAudioModePreset() whenever
 *    possible since it uses preconfigured values that are known to
 *    work.
 *
 *    Returns -1 on failure, and 0 on success.
 */
int YSetAudioModeValues(
      YConnection *con,
      int sample_size,  /* 8 or 16. */
      int channels,           /* 1 or 2. */
      int sample_rate,  /* In hz. */
      int direction,          /* 0 for play, 1 for record. */
      int allow_fragmenting,
      int num_fragments,
      int fragment_size /* In bytes. */
)
{
      int i;
      YEvent event;


      if(con == NULL)
          return(-1);
      if(con->fd < 0)
          return(-1);

      /* Send mode change values. */
      if(YNetSendAudioChangeValues(
          con,
          sample_size,
          channels,
          sample_rate,
          direction,
          allow_fragmenting,
          num_fragments,
          fragment_size
      ) <= 0)
          return(-1);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YAudioChange)
            {
                /* No need to be picky about Preset or Values
                 * type mode change, the mode *did* change is
                 * what we care about.
                 */
                break;
            } 
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}

/*
 *      Changes the Y server's Audio mode to the values specified by
 *    the preset Audio mode who matches the given name.
 *
 *      Returns -1 on failure, and 0 on success.
 */
int YChangeAudioModePreset(YConnection *con, const char *name)
{
      int i;
      YEvent event;


      if((con == NULL) || (name == NULL))
          return(-1);

      if(con->fd < 0)
          return(-1);

      /* Send change audio mode. */
      if(YNetSendAudioChangePreset(con, name) <= 0)
          return(-1);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YAudioChange)
            {
                /* If audio mode name is different then that
                 * implies a failure.
                 */
                if(strcasecmp(event.audio.mode_name, name))
                  return(-1);

                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }  
      }

      return(0);
}

/*
 *    Gets list of preset audio modes and their values.
 *
 *    Can return NULL on error.
 */
YAudioModeValuesStruct **YGetAudioModes(YConnection *con, int *count)
{
      int i, n;
      YEvent event;
      YAudioModeValuesStruct *amv_ptr;
      YAudioModeValuesStruct **ptr = NULL;


      if(count == NULL)
          return(NULL);
      else
          *count = 0;

      if(con == NULL)
          return(NULL);

      if(con->fd < 0)   
          return(NULL);

      /* Send get audio modes listing. */
      if(YNetSendListAudioModes(con) <= 0)
          return(NULL);

      /* Wait for response to get listing. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YListAudioModes)
            {
                if(event.audio.mode_name[0] == '\0')
                {
                  /* An audio mode listing with no name marks the
                   * end of the listing.
                   */
                  break;
                }
                else
                {
                  n = *count;
                  *count = n + 1;

                  ptr = (YAudioModeValuesStruct **)realloc(
                      ptr,
                      (*count) * sizeof(YAudioModeValuesStruct *)
                  );
                  if(ptr == NULL)
                  {
                      *count = 0;
                      return(NULL);
                  }

                  ptr[n] = (YAudioModeValuesStruct *)malloc(
                      sizeof(YAudioModeValuesStruct)
                  );
                  if(ptr[n] == NULL)
                  {
                      *count = n;
                      return(ptr);
                  }

                  amv_ptr = ptr[n];


                  strncpy(
                      amv_ptr->name,
                      event.audio.mode_name,
                      YAudioNameMax
                  );
                  amv_ptr->name[YAudioNameMax - 1] = '\0';

                  amv_ptr->sample_rate = event.audio.sample_rate;
                  amv_ptr->channels = event.audio.channels;
                  amv_ptr->sample_size = event.audio.sample_size;
                  amv_ptr->fragment_size_bytes = event.audio.fragment_size_bytes;
                  amv_ptr->direction = event.audio.direction;
                  amv_ptr->allow_fragmenting = event.audio.allow_fragmenting;
                  amv_ptr->num_fragments = event.audio.num_fragments;

                  /* Reset loop count to 0, we have more events
                   * to fetch.
                   */
                  i = 0;
                  continue;
                }
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(ptr);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(ptr);
}

/*
 *    Deletes the list of Audio modes.
 */
void YFreeAudioModesList(YAudioModeValuesStruct **list, int count)
{
      int i;

      for(i = 0; i < count; i++)
          free(list[i]);
      free(list);
}

/*
 *    Matches an Audio mode with the given values.
 *
 *    If an Audio mode is matched then buf will be set with the
 *    values of the matched Audio mode and True is returned,
 *    otherwise False is returned.
 */
Boolean YMatchAudioModeValues(
      YConnection *con,
      YAudioModeValuesStruct *buf,
      int sample_rate,
      int sample_size,
      int channels,
      int direction     /* 0 = play, 1 = record */
)
{
      int i, n;
      const YAudioModeValuesStruct *m;
      YAudioModeValuesStruct **mode = YGetAudioModes(con, &n);
      if(mode == NULL)
          return(False);

      /* Iterate through Audio modes */
      for(i = 0; i < n; i++)
      {
          m = mode[i];
          if(m == NULL)
            continue;

          /* This Audio mode's values match the given values? */
          if((m->sample_rate == sample_rate) &&
             (m->sample_size == sample_size) &&
             (m->channels == channels) &&
             (m->direction == direction) &&
             (buf != NULL)
          )
          {
            strncpy(buf->name, m->name, YAudioNameMax);
            buf->name[YAudioNameMax - 1] = '\0';

            buf->sample_rate = m->sample_rate;
            buf->channels = m->channels;
            buf->sample_size = m->sample_size;
            buf->fragment_size_bytes = m->fragment_size_bytes;
            buf->direction = m->direction;
            buf->allow_fragmenting = m->allow_fragmenting;
            buf->num_fragments = m->num_fragments;

            break;
          }
      }

      /* Delete Audio modes list */
      YFreeAudioModesList(mode, n);

      /* If an Audio mode was matched then return True */
      return((i < n) ? True : False);
}


/*
 *    Gets Y server statistics and stores them in the given
 *    YEventServerStats buffer.
 *
 *    Returns -1 on error and 0 on success.
 */
int YGetServerStats(YConnection *con, YEventServerStats *buf)
{
      int i;
      YEvent event;


      if((con == NULL) ||
         (buf == NULL)
      )
          return(-1);

      if(con->fd < 0)
          return(-1);


      /* Send request for server stats. */
      if(YNetSendGetServerStats(con) <= 0)
          return(-1);

      /* Wait for server stats event to come in. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YServerStats)
            {
                memcpy(
                  buf,
                  &event.serverstats,
                  sizeof(YEventServerStats)
                );
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }


      return(0);
}

/*
 *      Calculates the theoretical cycle (in microseconds) for
 *      the Y server given the Audio values.  The Audio values need
 *      not be the current Audio values of the recorder.
 *
 *      If the connection pointer con is NULL, then a general
 *      recommendation answer is returned. This value may not
 *      work with the recorder that you are connected to.
 */
long YCalculateCycle(
      YConnection *con,
      int sample_rate, int channels,
      int sample_size, int fragment_size
)
{
      if((sample_rate <= 0) ||
         (channels <= 0) ||
         (sample_size <= 0) ||
         (fragment_size <= 0)
      )
          return(0);

      return((long)(
          (Coefficient)1000000 / (Coefficient)(
            sample_rate * channels *
            ((sample_size == 16) ? 2 : 1)
          ) * (Coefficient)fragment_size / 1.5 
      ));
}

/*
 *    Set cycle in microseconds.
 *
 *    Returns -1 on error and 0 on success.
 */
int YSetCycle(YConnection *con, long us)
{
      int i;
      YEvent event;


      if(con == NULL)
          return(-1);
      if(con->fd < 0)
          return(-1);

      if(us < 1)
          us = 1;

      /* Send set cycle. */
      if(YNetSendCycleChange(con, us) <= 0)
          return(-1);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YCycleChange)
            {
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}


/*
 *    Syncs all of the Y server's resources, both the Y server and the
 *    client will also be synced.
 *
 *    If block is True then this operation will block (in finite time)
 *    to ensure that the Y server is up to sync.
 */
void YSyncAll(YConnection *con, Boolean block)
{
      int i;
      YEvent event;


      if(con == NULL)
          return;
      if(con->fd < 0)
          return;

      if(YNetSendSync(con, 0) <= 0)
          return;


      if(!block)
          return;

      /* Wait for server sync response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YSync)
            {
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return;
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }
}


/*
 *    Gets audio device statistics and stores them in
 *    the YEventAudioStats buffer.
 *
 *      Returns -1 on failure, and 0 on success.
 */
int YGetAudioStats(YConnection *con, YEventAudioStats *buf)
{
      int i;
      YEvent event;


      if((con == NULL) || (buf == NULL))
          return(-1);

      if(con->fd < 0)
          return(-1);

      /* Send request for audio stats. */
      if(YNetSendGetAudioStats(con) <= 0)
          return(-1);

      /* Wait for audio stats event to come in. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YAudioStats)
            {
                memcpy(
                  buf,
                  &event.audiostats,
                  sizeof(YEventAudioStats)
                );
                break;
            }
            else if((event.type == YDisconnect) ||
                    (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}


/*
 *    Adds the IP address specified by ip to the Y server's access list.
 *
 *      Returns -1 on failure, and 0 on success.
 */
int YAddHost(YConnection *con, YIPUnion *ip)
{
      int i;
      YEvent event;


      if(con == NULL)
          return(-1);
      if(con->fd < 0)
          return(-1);
      if(ip == NULL)
          return(-1);


      /* Send add host. */
      if(YNetSendSetHost(con, YSetHostAdd, ip) <= 0)
          return(-1);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YSetHost)
            {
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}

/*
 *      Removes the IP address specified by ip from the Y server's access
 *    list. If the specified ip does not exist in the Y server's access
 *    list then no operation will be performed.
 *
 *      Returns -1 on failure, and 0 on success.
 */
int YRemoveHost(YConnection *con, YIPUnion *ip)
{
      int i;
      YEvent event;


      if(con == NULL)
          return(-1);
      if(con->fd < 0)
          return(-1);
      if(ip == NULL)
          return(-1);


      /* Send remove host. */
      if(YNetSendSetHost(con, YSetHostRemove, ip) <= 0)
          return(-1);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YSetHost)
            {
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}


/*
 *    Sets specified mixer channel values.
 */
int YSetMixerChannel(
      YConnection *con,
      int mixer_channel_code,
      Coefficient value1, Coefficient value2
) 
{
      if(con == NULL)
          return(-1);
      if(con->fd < 0)
          return(-1);

      /* Sanitize values. */
      if(mixer_channel_code < 0)
          return(-1);

      if(value1 < 0)
          value1 = 0;
      if(value1 > 1)
          value1 = 1;

      if(value2 < 0)
          value2 = 0;
      if(value2 > 1) 
          value2 = 1;

      /* Send set mixer device. */
      if(YNetSendSetMixerChannel(
          con,
          mixer_channel_code,
          value1, value2, 0.0, 0.0
      ) <= 0)
          return(-1);

      /* Do not catch response, calling function may want to have it. */

      return(0);
}

/*
 *    Same as YSetMixerChannel(), except that it accepts four mixer
 *    channels.
 */
int YSetMixerChannelQuad(
      YConnection *con,
      int mixer_channel_code,
      Coefficient value1, Coefficient value2,
      Coefficient value3, Coefficient value4
)
{
      if(con == NULL)
          return(-1);
      if(con->fd < 0)
          return(-1);

      /* Sanitize values. */
      if(mixer_channel_code < 0)
          return(-1);

      if(value1 < 0)
          value1 = 0;
      if(value1 > 1)
          value1 = 1;

      if(value2 < 0)
          value2 = 0;
      if(value2 > 1)
          value2 = 1;

      if(value3 < 0)
          value3 = 0;
      if(value3 > 1)
          value3 = 1;

      if(value4 < 0)
          value4 = 0;
      if(value4 > 1)
          value4 = 1;

      /* Send set mixer device. */
      if(YNetSendSetMixerChannel(
          con,
          mixer_channel_code,
          value1, value2, value3, value4
      ) <= 0)
          return(-1);

      /* Do not catch response, calling function may want to have it. */

      return(0);
}

/*
 *      Gets specified mixer channel values.
 */
int YGetMixerChannel(
      YConnection *con,
      int mixer_channel_code,
      Coefficient *value1, Coefficient *value2
)
{
      int i;
      YEvent event;
      
          
      if(con == NULL)
          return(-1);
      if(con->fd < 0)
          return(-1);


      /* Send request for mixer device values. */
      if(YNetSendGetMixerChannel(con, mixer_channel_code) <= 0)
          return(-1);


      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YMixerChannel)
            {
                if(event.mixer.code != mixer_channel_code)
                  return(-1);

                if((value1 != NULL) && (YMixerValues > 0))
                  *value1 = event.mixer.value[0];
                if((value2 != NULL) && (YMixerValues > 1))
                  *value2 = event.mixer.value[1];

                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}

/*
 *    Same as YGetMixerChannelQuad(), except that up to four
 *    channels can be fetched.
 */
int YGetMixerChannelQuad(
      YConnection *con,
      int mixer_channel_code,
      Coefficient *value1, Coefficient *value2,
      Coefficient *value3, Coefficient *value4
)
{
      int i;
      YEvent event;


      if(con == NULL)
          return(-1);
      if(con->fd < 0)
          return(-1);


      /* Send request for mixer device values. */
      if(YNetSendGetMixerChannel(con, mixer_channel_code) <= 0)
          return(-1);


      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YMixerChannel)
            {
                if(event.mixer.code != mixer_channel_code)
                  return(-1);

                if((value1 != NULL) && (YMixerValues > 0))
                  *value1 = event.mixer.value[0];
                if((value2 != NULL) && (YMixerValues > 1))
                  *value2 = event.mixer.value[1];
                if((value3 != NULL) && (YMixerValues > 2))
                  *value3 = event.mixer.value[2];
                if((value4 != NULL) && (YMixerValues > 3))
                  *value4 = event.mixer.value[3];

                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}

/*
 *    Starts playing the sound object specified by path, returns
 *    the YID identifying the sound object being played or YIDNULL on
 *    failure.
 */
YID YStartPlaySoundObjectSimple(YConnection *con, const char *path)
{
      YEventSoundPlay value;

      value.flags =     YPlayValuesFlagYID |
                  YPlayValuesFlagPosition |
                  YPlayValuesFlagLength |
                  YPlayValuesFlagRepeats |
                  YPlayValuesFlagTotalRepeats |
                  YPlayValuesFlagVolume |
                  YPlayValuesFlagSampleRate;

      value.yid = YIDNULL;          /* Ignored by server. */
      value.position = 0;           /* Ignored by server. */
      value.length = 0;       /* Ignored by server. */
      value.repeats = 0;            /* Ignored by server. */
      value.total_repeats = 1;
      value.left_volume = 1.0;
      value.right_volume = 1.0;
      value.sample_rate = 0;

      return(YStartPlaySoundObject(con, path, &value));
}

/*
 *    Starts playing the sound object specified by path, returns
 *    the YID indentifying the sound object being played or YIDNULL on
 *    failure.
 *
 *    The only criteria for a success here is that the sound object
 *    exist.
 */
YID YStartPlaySoundObject(
      YConnection *con,
      const char *path, /* Path on disk on server's computer. */
      YEventSoundPlay *value
)
{
      int i;
      YVolumeStruct volume;
      YID yid;
      YEvent event;
      YEventSoundPlay v2;


      if((con == NULL) || (path == NULL) || (value == NULL))
          return(YIDNULL);

      if(con->fd < 0)
          return(YIDNULL);

      /* Set up default play values, copy input value structure
       * values to the structure v2 (which will be passed to
       * YNetSendSoundPlay().
       */
      v2.flags =  YPlayValuesFlagYID |
                  YPlayValuesFlagPosition |
                  YPlayValuesFlagLength |
                  YPlayValuesFlagRepeats |
                  YPlayValuesFlagTotalRepeats |
                  YPlayValuesFlagVolume |
                  YPlayValuesFlagSampleRate;

      v2.yid = YIDNULL; /* Ignored by server. */
      v2.position = 0;  /* Ignored by server. */
      v2.length = 0;    /* Ignored by server. */
      v2.repeats = 0;   /* Ignored by server. */
      v2.total_repeats = 1;
      v2.left_volume = 1.0;
      v2.right_volume = 1.0;
      v2.back_left_volume = 1.0;
      v2.back_right_volume = 1.0;
      v2.sample_rate = 0;


      if(value->flags & YPlayValuesFlagPosition)
      {
          v2.position = value->position;
          if(v2.position < 0)
            v2.position = 0;
      }

      if(value->flags & YPlayValuesFlagTotalRepeats)
      {
          v2.total_repeats = value->total_repeats;
          if(v2.total_repeats <= 0)
            v2.total_repeats = -1;
      }

      if(value->flags & YPlayValuesFlagVolume)
      {
          v2.left_volume = CLIP(value->left_volume, 0.0, 1.0);
          v2.right_volume = CLIP(value->right_volume, 0.0, 1.0);
          v2.back_left_volume = CLIP(value->back_left_volume, 0.0, 1.0);
          v2.back_right_volume = CLIP(value->back_right_volume, 0.0, 1.0);
      }
      /* Set volume structure. */
      volume.left = (Coefficient)v2.left_volume *
          (Coefficient)((u_int16_t)-1);
      volume.right = (Coefficient)v2.right_volume *
          (Coefficient)((u_int16_t)-1);
      volume.back_left = (Coefficient)v2.back_left_volume *
          (Coefficient)((u_int16_t)-1);
      volume.back_right = (Coefficient)v2.back_right_volume *
          (Coefficient)((u_int16_t)-1);

      if(value->flags & YPlayValuesFlagSampleRate)
      {
          v2.sample_rate = MAX(value->sample_rate, 0);
      }


      /* Increment yid dispense number and get new yid. */
      con->prev_generated_yid++;
      yid = con->prev_generated_yid;

      /* Send request to start playing. */
      if(YNetSendSoundPlay(
          con, yid, path,
          v2.position,
          &volume,
          v2.sample_rate,
          v2.total_repeats
      ) <= 0)
          return(YIDNULL);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YSoundObjectPlay)
            {
                if(event.play.yid == YIDNULL)
                {
                  /* Confirmation recieved but indicated that the
                   * play failed.
                   */
                  return(YIDNULL);
                }
                else
                {
                  /* Put back event so client can receive it. */
                  YPutBackEvent(con, &event);
                }
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(YIDNULL);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      /* Return with the yid of the play object. */
      return(yid);
}

/*
 *    Gets sound object attributes, returns -1 on error or
 *    0 on success.
 *
 *    Note, the sound object need not be playing in order to
 *    fetch its attributes.
 */
int YGetSoundObjectAttributes(
      YConnection *con,
      const char *path,
      YEventSoundObjectAttributes *buf 
)
{
      int i;
      YEvent event;


      if((con == NULL) ||
         (path == NULL)
      )
          return(-1);

      if(con->fd < 0)
          return(-1);

      /* Send request for sound object attributes. */
      if(YNetSendGetSoundObjectAttributes(con, path) <= 0)
          return(-1);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YSoundObjectAttributes)
            {
                const char *ev_path_ptr = event.sndobjattributes.path;
                if(*ev_path_ptr == '\0')
                {
                  /* Empth path implies failed. */
                  return(-1);
                }
                /* Returned path stored in the event needs to
                 * match what we sent or else we should
                 * interprite this as an error.
                 */
                else if(!strcmp(ev_path_ptr, path))
                {
                  memcpy(
                      buf,
                      &event.sndobjattributes,
                      sizeof(YEventSoundObjectAttributes)
                  );
                }
                else
                {
                  /* Returned path in event does mot match the path
                   * that was sent, so consider this an error.
                   */
                  return(-1);
                }
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}

/*
 *    Modifies the play values of the sound object specified by yid
 *    that is already playing.
 */
void YSetPlaySoundObjectValues(
      YConnection *con, YID yid, YEventSoundPlay *value
)
{
      if((con == NULL) || (yid == YIDNULL) || (value == NULL))
          return;

      if(con->fd < 0)
          return;

      value->flags |= YPlayValuesFlagYID;
      value->yid = yid;

      /* Send set play sound object values. */
      if(YNetSendSetSoundObjectPlayValues(con, value) <= 0)
          return;

      /* Do not wait for response, calling functions may want to
       * recieve it.
       */
}

/*
 *    Gets the play values of the sound object specified by yid
 *    that is already playing.
 *
 *    Returns 0 on success or non-zero on error.
 */
int YGetPlaySoundObjectValues(
      YConnection *con, YID yid, YEventSoundPlay *value
)
{
      int i;
      YEvent event;

      if((con == NULL) || (yid == YIDNULL) || (value == NULL))
          return(-1);

      if(con->fd < 0)
          return(-1);

      /* Send request for sound object values. */
      if(YNetSendGetSoundObjectPlayValues(con, yid) <= 0)
          return(-1);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YSoundObjectPlayValues)
            {
                const YEventSoundPlay *play = &event.play;

                if(play->yid == YIDNULL)
                  return(-1);

                memcpy(value, play, sizeof(YEventSoundPlay));
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(-1);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(0);
}

/*
 *      Destroys (stops/kills/terminates) the sound object
 *      being played, indetified by yid. If the yid does not
 *      match any sound object currently being played, no
 *      operation will be performed.
 */
void YDestroyPlaySoundObject(YConnection *con, YID yid)
{
      if((con == NULL) || (yid == YIDNULL))
          return;

      if(con->fd < 0)
          return;

      if(YNetSendSoundKill(con, yid) <= 0)
          return;

      /*  Do not catch event response for this, calling function
       *  may want to have it.
       */
}


/*
 *      Sends a client message.
 *
 *      Returns -1 on failure, and 0 on success.
 */
int YSendClientMessage(
      YConnection *con,
      Boolean notify_self,    /* Send ourself this YClientMessage event too. */
      int format,             /* One of YClientMessageFormat*. */
      int type,               /* One of YClientMessageType*, note that
                         * clients can also define their own types.
                         * so unexpected values may appear.
                         */
      const char *message,    /* Message. */
      int length              /* Length of message in bytes. */
)
{
      if(con == NULL)
          return(-1);

      if(con->fd < 0)
          return(-1);

      /* Send client message. */
      if(YNetSendClientMessage(
          con, notify_self, format, type, message, length
      ) <= 0)
          return(-1);

      return(0);
}

/*
 *    Opens the shared memory segment of the sound buffer on the Y
 *    server.
 *
 *    Returns the pointer to the memory segment, the length of the
 *    buffer in bytes, and the shared memory segment id.
 *
 *    The returned pointer must be closed by calling YSHMClose().
 *
 *    Can return NULL on error.
 */
void *YSHMOpenSound(YConnection *con, int *length, int *id)
{
      int i;
      YEvent event;
      void *ptr = NULL;

      if(length != NULL)
          *length = 0;
      if(id != NULL)
          *id = -1;

      if(con == NULL)
          return(NULL);

      if(con->fd < 0)
          return(NULL);

      /* Send request for sound object attributes. */
      if(YNetSendYSHMSoundOpen(con) <= 0)
          return(NULL);

      /* Wait for response. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if(event.type == YSHMSound)
            {
                YEventYSHMSound *yshmsound = &event.yshmsound;

                /* Open? */
                if(yshmsound->minor_op_code == YSHMSoundOpen)
                {
                  int _id = yshmsound->shm_id;
                  int _length;
                  if(_id > -1)
                  {
                      ptr = SHMRef(_id, &_length);
                      if(ptr != NULL)
                      {
                        if(length != NULL)
                            *length = _length;
                        if(id != NULL)
                            *id = _id;
                      }
                  }
                }
                break;
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(NULL);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }

      return(ptr);
}
/*
 *    Closes the shared memory segment of the sound buffer that was
 *    previously opened by a call to YSHMOpenSound().
 */
void YSHMCloseSound(YConnection *con, void *ptr)
{
      if(con == NULL)
          return;

      if(con->fd < 0)
          return;

      SHMUnref(ptr);
}

/*
 *    Plays audio CD track specified by track_number.
 *
 *      Returns -1 on failure, and 0 on success.
 */
int YPlayAudioCDTrack(YConnection *con, int track_number)
{
      if(con == NULL)
          return(-1);

      if(con->fd < 0)
          return(-1);

      /* Send play audio CD track. */
      if(YNetSendAudioCDPlayTrack(con, track_number) <= 0)
          return(-1);

      /* Do not catch event response for this, calling function
       * may want to have it.
       */

      return(0);
}
/*
 *    Stops audio CD playing.
 *
 *      Returns -1 on failure, and 0 on success.
 */
int YStopAudioCD(YConnection *con)
{
      if(con == NULL)
          return(-1);

      if(con->fd < 0)
          return(-1);

      /* Send stop audio CD. */
      if(YNetSendAudioCDStop(con) <= 0)
          return(-1);

      /* Do not catch event response for this, calling function
       * may want to have it.
       */

      return(0);
}
/*
 *    Ejects audio CD.
 *
 *      Returns -1 on failure, and 0 on success.
 */
int YEjectAudioCD(YConnection *con)
{
      if(con == NULL)
          return(-1);

      if(con->fd < 0)
          return(-1);

      /* Send eject audio CD. */
      if(YNetSendAudioCDEject(con) <= 0)
          return(-1);

      /* Do not catch event response for this, calling function
       * may want to have it.
       */

      return(0);
}

/*
 *      Gets list of audio CD tracks.
 *
 *      Can return NULL on error.
 */
YAudioCDTrackStruct **YGetAudioCDTracks(
      YConnection *con, int *count
)
{
      int i, n;
      YEvent event;
      YAudioCDTrackStruct *t, **ptr = NULL;


      if(count == NULL)
          return(NULL);
      else
          *count = 0;

      if(con == NULL)
          return(NULL);

      if(con->fd < 0)   
          return(NULL);

      /* Send get audio CD tracks listing. */
      if(YNetSendListAudioCDTracks(con) <= 0)
          return(NULL);

      /* Wait for response to get listing. */
      for(i = 0; i < DEF_EVENT_FETCH_RETRIES; i++)
      {
          if(YGetNextEvent(con, &event, True) > 0)
          {
            if((event.type == YAudioCDTracksList) &&
               (event.audiocdstats.minor_op_code == YAudioCDTracksListSet)
            )
            {
                YEventAudioCDStats *acd_stats = &event.audiocdstats;
                if(acd_stats->track_number <= 0)
                {
                  /* End of listing. */
                  break;
                }
                else
                {
                  n = *count;
                  *count = n + 1;

                  ptr = (YAudioCDTrackStruct **)realloc(
                      ptr,
                      (*count) * sizeof(YAudioCDTrackStruct *)
                  );
                  if(ptr == NULL)
                  {
                      *count = 0;
                      return(NULL);
                  }

                  ptr[n] = t = (YAudioCDTrackStruct *)malloc(
                      sizeof(YAudioCDTrackStruct)
                  );
                  if(t == NULL)
                  {
                      *count = n;
                      return(ptr);
                  }

                  t->number = acd_stats->track_number;
                  t->start_time = acd_stats->track_start_time;
                  t->length = acd_stats->track_length;
                  strncpy(
                      t->name, acd_stats->track_name,
                      YAudioCDTrackNameMax
                  );
                  t->name[YAudioCDTrackNameMax - 1] = '\0';

                  /* Reset loop count to 0, we have more events
                   * to fetch.
                   */
                  i = 0;
                  continue;
                }
            }
            else if((event.type == YDisconnect) ||
                  (event.type == YShutdown)
            )
            {
                return(ptr);
            }

            /* Put back event and discount this loop. */
            YPutBackEvent(con, &event);
            i--;
          }
      }


      return(ptr);
}

/*
 *      Deallocates the list of Audio CD track structures and the
 *      pointer array.
 */
void YFreeAudioCDTracksList(YAudioCDTrackStruct **list, int count)
{
      int i;

      for(i = 0; i < count; i++)
          free(list[i]);
      free(list);
}

/*
 *    Disconnects from YIFF server and frees all allocated
 *    resources.
 *
 *      The pointer con may no longer be used after a call to this
 *      function.
 */
void YCloseConnection(YConnection *con, Boolean no_shutdown)
{
      int i;
      YEvent event;

      if(con == NULL)
          return;

      /* If we started the server, then we should shut it down. */
      if(con->we_started_server &&
         !no_shutdown
      )
      {
          if(con->fd > -1)
          {
            YNetSendShutdown(con, 0);

              /* Wait for shutdown event (for 30 seconds). */
              for(i = 0; i < 60; i++)
              {
                if(YGetNextEvent(con, &event, False) > 0)
                {
                  /* Is it a YShutdown or YDisconnect event? */
                  if((event.type == YShutdown) ||
                     (event.type == YDisconnect)
                  )
                  {
                      break;
                  }
                }

                /* Resend shutdown command. */
                YNetSendShutdown(con, 0);

                usleep(500000);
            }

            /* Close connection as needed. */
            if(con->fd > -1)
            {
                close(con->fd);
                con->fd = -1;
            }
          }
      }
      else
      {
          if(con->fd > -1)
          {
            YNetSendDisconnect(con, 0);

            /* Close connection. */
            if(con->fd > -1)
            {
                close(con->fd);
                con->fd = -1;
            }
          }
      }

      /* Free connection structure and its resources. */
      YIFF_FREE_CON(con);
      con = NULL;
}


/*
 *    Shuts down the YIFF server, thus disconnecting and
 *    freeing all allocated resources.
 *
 *    The pointer con may no longer be used after a call to this
 *    function.
 */
void YShutdownServer(YConnection *con)
{
      int i;
      YEvent event;


      if(con == NULL)
          return;

      /* Is connected? */
      if(con->fd > -1)
      {
          YNetSendShutdown(con, 0);

          /* Wait for YShutdown or YDisconnect event (for 30 seconds). */
          for(i = 0; i < 60; i++)
          {
            if(YGetNextEvent(con, &event, False) > 0)
            {
                /* Is it a YShutdown or YDisconnect event? */
                if((event.type == YShutdown) ||
                   (event.type == YDisconnect)
                )
                {
                  break;
                }
            }

              /* Resend shutdown command. */
            YNetSendShutdown(con, 0);

            usleep(500000);   /* Wait half a second. */
          }

          /* Close connection as needed. */
          if(con->fd > -1)
          {
            close(con->fd);
            con->fd = -1;
          }
      }

      /* Free connection structure and its resources as needed. */
      YIFF_FREE_CON(con);
      con = NULL;
}



/*
 *    Get next (oldest) event from the server and stores it on
 *    the pointer to the YEvent event.
 *
 *    If block is set to True, then execution will be
 *    blocked untill next event is recieved.
 *
 *    If the recieved event is of type YDisconnect or YShutdown then
 *    the given con structure's connection descriptor will be closed
 *    and reset to -1.
 */
int YGetNextEvent(YConnection *con, YEvent *event, Boolean block)
{
      int i, status;
      YEvent *src_event_ptr, *tar_event_ptr;


      if((con == NULL) || (event == NULL))
          return(0);

      if(con->fd < 0)
      {
          /* Connection descriptor is -1 so return event as a
           * YDisconnect event.
           */
          YSetEventToBeDisconnect(event);
          return(1);
      }

      /* Sanitize total queued events. */
      if(con->total_queued_events < 0)
          con->total_queued_events = 0;


      do
      {
          /* Get new events and put them into the queue. Note that
           * this function may close the connection if a YDisconnect
           * or YShutdown event is recieved. In which case the con->fd
           * will be set to -1.
           */
          status = YNetRecv(con);
          /* Non-error (got 0 or more events) and connection still
           * valid?
           */
          if((status < 0) ||
             (con->fd < 0)
          )
          {
            /* Either a serious recieve error occured or the
             * connection has been disconnected by YNetRecv().
             *
             * The socket should now be -1, force close if it is
             * not.
             */
            if(con->fd > -1)
            {
                close(con->fd);
                con->fd = -1;
            }

            /* We need to make sure the event returned is either
             * a YDisconnect or YShutdown.
             */

            /* Are there any queued events to be reported? */
            if(con->total_queued_events > 0)
            {
                /* Yes we got atleast one. */

                /* Copy OLDEST queued event to event structure. */
                YIFF_COPY_EVENTS(event, &(con->queued_event[0]));

                /* Don't shift events in queue, instead dealloate
                 * all queued events.
                 */
                free(con->queued_event);
                con->queued_event = NULL;
                con->total_queued_events = 0;

                /* Event not a YDisconnect and YShutdown? */
                if((event->type != YDisconnect) &&
                   (event->type != YShutdown)
                )
                  YSetEventToBeDisconnect(event);
            }
            else
            {
                /* No events queued, so report a YDisconnect. */
                YSetEventToBeDisconnect(event);
            }

              return(1);
          }

          /* Got atleast one complete event? */
          if(con->total_queued_events > 0)
          {
            /* Yes we got atleast one. */

              /* Copy OLDEST queued event to event structure. */
              YIFF_COPY_EVENTS(event, &(con->queued_event[0]));


              /* Decrement number of and shift queued events. */
              con->total_queued_events--;

            tar_event_ptr = &(con->queued_event[0]);
            /* src_event_ptr may be invalid but if so then we do
             * not access it.
             */
            src_event_ptr = &(con->queued_event[1]);

              for(i = 0;
                i < con->total_queued_events;
                i++, tar_event_ptr++, src_event_ptr++
            )
                YIFF_COPY_EVENTS(
                    tar_event_ptr,
                    src_event_ptr
                );

            /* Reallocate queued event pointers. */
            if(con->total_queued_events > 0)
            {
                con->queued_event = (YEvent *)realloc(
                  con->queued_event,
                  con->total_queued_events * sizeof(YEvent)
                );
                if(con->queued_event == NULL)
                {
                  con->total_queued_events = 0;
                }
            }
            else
            {
                free(con->queued_event);
                con->queued_event = NULL;
                con->total_queued_events = 0;
            }

            /* Report that we got event. */
              return(1);
          }
          else
          {
            if(block)
                usleep(100);
          }

      } while(block);


      return(0);
}


/*
 *    Puts back the event onto the queue as the newest (highest
 *    index) event.
 *
 *    So all other older events (if any) will be returned before this
 *    one when YGetNextEvent() is called.
 */
void YPutBackEvent(
      YConnection *con,
      YEvent *event
)
{
      int n;


      if((con == NULL) ||
         (event == NULL)
      )
          return;

      if(con->fd < 0)
          return;


      /* Sanitize total queued events. */
      if(con->total_queued_events < 0)
          con->total_queued_events = 0;

      /* Increment total. */
      n = con->total_queued_events;
      con->total_queued_events++;

      /* Check if exceeded maximum allowed queued events. */
      if(con->total_queued_events > YQueuedEventsMax)
      {
          fprintf(stderr,
 "YPutBackEvent(): Connection 0x%.8x: Limit of %i queued events exceeded.\n",
            (u_int32_t)con,
            YQueuedEventsMax
          );
          con->total_queued_events = YQueuedEventsMax;

          return;
      }

      /* Allocate a new queued event. */
      con->queued_event = (YEvent *)realloc(
          con->queued_event,
          con->total_queued_events * sizeof(YEvent)
      );
      if(con->queued_event == NULL)
      {
          con->total_queued_events = 0;
          return;
      }


      /* Copy input event values to new queued event position. */
      YIFF_COPY_EVENTS(&con->queued_event[n], event);
}

Generated by  Doxygen 1.6.0   Back to index