A simple example

Here's a simple example of a client that has a connection open to a server and tries to read data from it. After reading from the descriptor, the client goes off to do something else (possibly causing a delay), and then returns to read again.

During this window of delay, the server might have died and returned, in which case the initial connection to the server (that has died) is now stale.

But since the connection has been made HA-aware, and a recovery function has been associated with it, the connection is able to reestablish itself.



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ha/cover.h>

#define SERVER "/path/to/server"

typedef struct handle {
    int nr;
} Handle ;

int recover_conn2(int oldfd, void *hdl)
{
    int newfd;
    Handle *thdl;
    thdl = (Handle *)hdl;
    printf("recovering for fd %d  inside function 2\n",oldfd);
    /* re-open the connection */
    newfd = ha_reopen(oldfd, SERVER, O_RDONLY);
  /* perform any other kind of state re-construction */
    (thdl->nr)++;
    return(newfd);
}

int recover_conn(int oldfd, void *hdl)
{
    int newfd;
    Handle *thdl;
    thdl = (Handle *)hdl;
    printf("recovering for fd %d inside function\n",oldfd);
    /* re-open the connection */
    newfd = ha_reopen(oldfd, SERVER, O_RDONLY);
    /* perform any other kind of state reconstruction */
    (thdl->nr)++;
    return(newfd);
}

int main(int argc, char *argv[])
{
    int status;
    int fd;
    int fd2;
    int fd3;
    Handle hdl;
    char buf[80];
    int i;

    hdl.nr = 0;
    /* open a connection and make it HA aware */
    fd = ha_open(SERVER, O_RDONLY,recover_conn, (void *)&hdl, 0);
    if (fd < 0) {
        printf("could not open %s\n", SERVER);
        exit(-1);
    }

    printf("fd = %d\n",fd);
  /* Dup the FD. the copy will also be HA aware */
    fd2 = ha_dup(fd);

    printf("dup-ped fd2 = %d\n",fd2);
    printf("before sleeping first time\n");

  /*
   Go to sleep... 
   Possibly the SERVER might die and return in this little
   time period.
  */
    sleep(15); 

  /*
   reading from dup-ped fd
   this should work just normally if SERVER has not died.
   But if the SERVER has died and returned, the 
   initial read will fail, but the recovery function
   will be called, and it will re-establish the
   connection, and then re-establish the current
   file position and then re-issue the read call
   which should succeed now.
  */

    printf("trying to read from %s using fd %d\n",SERVER, fd2);
    status = read(fd2,buf,30);
    if (status < 0)
        printf("error: %s\n",strerror(errno));

  /*
   fd and fd2 are dup-ped fd's
   changing the recovery function for fd2
   From this point forwards, the recovery (if at all)
   will performed using "recover_conn2" as the recovery
   function.
  */

    status = ha_attach(fd2, recover_conn2, (void *)&hdl, HAREPLACERECOVERYFN);

    ha_close(fd); /* close fd */

  /* open a new connection */
    fd = open(SERVER, O_RDONLY);
    printf("New fd = %d\n",fd);

  /* make it HA aware. */
    status = ha_attach(fd, recover_conn, (void *)&hdl, 0);

    printf("before sleeping again\n");

  /* copy it again */
    fd3 = ha_dup(fd);

  /* go to sleep...possibly another option for the server to fail. */
    sleep(15);

  /* 
   get rid of one of the fd's
   we still have a copy in fd3, which must have the 
   recovery functions associated with it.
  */
    ha_close(fd);

    printf("trying to read from %s using fd %d\n",SERVER, fd3);

  /*
   if it fails, the call will generate a call back to the
   recovery function "recover_conn"
  */
    status = read(fd3,buf,30); 
    if (status < 0)
        printf("error: %s\n",strerror(errno));

    printf("trying to read from %s once more using fd %d\n",SERVER, fd2);

  /*
   if this call fails, recovery will be via the 
   second function "recover_conn2", since we replaced
   the function for fd2.
  */
    status = read(fd2,buf,30); 
    if (status < 0)
        printf("error: %s\n",strerror(errno));

  /* close the fd2, and detach it from the HA lib */
    ha_close(fd2);

  /*
   finally print out our local statistics that we have been
   retaining along the way.
  */
    printf("total recoveries, %d\n",hdl.nr);
    exit(0);
}