/*******Program to test rocovery of the connection Id returned by name_open()*******/ /* * client_recovery.c * * This is a simple client program that will periodically send a small * amount of data to a server. It uses the HA client library to setup * recovery for the connection Id returned by name_open(), so that on failure * and restart of the server this client will just continue working. * */ #include #include #include #include #include #include #define EOK 0 #define STRING_LEN 10 #define SERVER "server" typedef struct handle { int nr; } Handle ; typedef union { struct _pulse puls; char string[STRING_LEN + 1]; }message_t; /* our recovery function */ int recover_conn(int oldcd, void *hdl) { int newfd = 0; Handle *hd; hd = (Handle *)hdl; struct _server_info info; int coid; name_close(oldcd);/* closes the previous connection */ /* Go to sleep... Possibly the SERVER might die and return in this little time period. */ sleep(1); newfd = name_open(SERVER,0); /* opens a new connection */ /*Note: Using ha_ReConnectAttach(..) resulted memory fault(),Why is it so?, i.e coid = name_open(SERVER,0); if(ConnectServerInfo( getpid(), coid , &info ) == coid) { printf("\nGot server info:%d,%d,%d\n",info.pid,info.scoid,info.coid); } newfd = ha_ReConnectAttach(oldcd,0,info.pid,info.chid,0, 0);*/ if(newfd == -1) { printf("error occured\n"); } else { printf("Recover Successfull, New fd= %d\n",newfd); } (hd->nr)++; return(newfd); } int main(int argc, char* argv[]) { int newfd; message_t msg; int coid; int fd; int status; Handle hdl; char recbuf[100]; coid = name_open(SERVER,0); /*attaches a recovery function to a connection coid */ fd = ha_attach(coid, recover_conn,(void *)&hdl ,0 ); if(fd==-1) { printf("Error in ha_attach().......Exitting\n"); exit(EXIT_FAILURE); } strcpy(msg.string,"hello"); while(1) { //kill server and restart it! sleep(3); printf("Client is sending string: '%s' to server \n", msg.string); status = MsgSend( coid, &msg, sizeof(msg),recbuf,sizeof(recbuf)); if(status == -1) { printf("\nError in MsgSending....Exitting"); exit(EXIT_FAILURE); } printf("Client received the following from server = '%s' \n",recbuf ); } ha_close(fd); printf("Total recoveries, %d\n",hdl.nr); return EXIT_SUCCESS; } /*********To test recovery of the file descriptor using ha_open() & ha_reopen() API ********/ /* * ha_client.c * * This is a simple client program that will periodically read a small * amount of data from a device. It uses the HA client library to setup * recovery for that fd, so that on failure and restart of the server this * client will just continue working. * * It opens the device to be read based on a command line option. * */ #include #include #include #include #include #include void options (int argc, char **argv); int recover_read_fd( int, void * ); /* our recovery function */ char *server_path; /* the server that we will be reading from, set in options : Eg: /dev/Null*/ int optv; int main(int argc, char **argv) { int data, server_fd, bytes; options( argc, argv ); server_fd = ha_open( server_path, O_RDONLY, recover_read_fd, server_path,0 ); if (-1 == server_fd ) { perror("opening device"); exit( EXIT_FAILURE ); } while(1) { bytes = read( server_fd, &data, sizeof(data) ); if (-1 == bytes ) { perror("read"); printf("oops... we lost our fd...\n"); exit( EXIT_FAILURE ); } printf("data read: %d\n", data ); sleep(1); } } int recover_read_fd( int old_fd, void *hdl ) { int new_fd; char *fname; fname = (char *) hdl; if( optv ) printf("trying to recover fd %d for filename %s\n", old_fd, fname ); /* a short delay to allow the server to restart, could be a retry loop */ delay(100); new_fd = ha_reopen( old_fd, fname, O_RDONLY ); return new_fd; } /* * options * * This routine handles the command line options. * For our simple /dev/redirect, we support: * -v verbose operation * dev_name where to read from */ void options (int argc, char **argv) { int opt; int i; optv = 0; i = 0; while (optind < argc) { while ((opt = getopt (argc, argv, "v")) != -1) { switch (opt) { case 'v': optv = 1; break; } } if (optind < argc) { server_path = argv[optind]; printf("server path is %s\n", server_path ); break; } else { printf("need to give a device to open\n"); exit(1); } } } /**************************To create Null Resource manager****************************/ /* * null.c * * This is a slightly modified version of null that puts a sleep in the * io_read handler to allow a chance for null to be killed while a client * is blocked on it. * * (Note that ours is called /dev/Null instead of /dev/null; this * is because /dev/null already exists and is shipped as part of * Neutrino). * * This module contains all of the functions necessary. * */ #include #include #include #include #include #include #include #include #include void options (int argc, char **argv); /* * these prototypes are needed since we are using their names in main () */ int io_open (resmgr_context_t *ctp, io_open_t *msg, RESMGR_HANDLE_T *handle, void *extra); int io_read (resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb); int io_write(resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *ocb); /* * our connect and I/O functions */ resmgr_connect_funcs_t connect_funcs; resmgr_io_funcs_t io_funcs; /* * our dispatch, resource manager and iofunc variables */ dispatch_t *dpp; resmgr_attr_t rattr; dispatch_context_t *ctp; iofunc_attr_t ioattr; char *progname = "null"; int optv; // -v for verbose operation main (int argc, char **argv) { int pathID; printf ("%s: starting...\n", progname); options (argc, argv); /* * allocate and initialize a dispatch structure for use by our * main loop */ dpp = dispatch_create (); if (dpp == NULL) { fprintf (stderr, "%s: couldn't dispatch_create: %s\n", progname, strerror (errno)); exit (1); } /* * set up the resource manager attributes structure, we'll * use this as a way of passing information to resmgr_attach(). * For now, we just use defaults. */ memset (&rattr, 0, sizeof (rattr)); /* using the defaults for rattr */ /* * intialize the connect functions and I/O functions tables to * their defaults and then override the defaults with the * functions that we are providing. */ iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_funcs, _RESMGR_IO_NFUNCS, &io_funcs); io_funcs.read = io_read; io_funcs.write = io_write; /* * call resmgr_attach to register our prefix with the * process manager, and also to let it know about our connect * and I/O functions. * * On error, returns -1 and errno is set. */ iofunc_attr_init (&ioattr, S_IFCHR | 0666, NULL, NULL); pathID = resmgr_attach (dpp, &rattr, "/dev/Null", _FTYPE_ANY, 0, &connect_funcs, &io_funcs, &ioattr); if (pathID == -1) { fprintf (stderr, "%s: couldn't attach pathname: %s\n", progname, strerror (errno)); exit (1); } ctp = dispatch_context_alloc (dpp); while (1) { if ((ctp = dispatch_block (ctp)) == NULL) { fprintf (stderr, "%s: dispatch_block failed: %s\n", progname, strerror (errno)); exit (1); } dispatch_handler (ctp); } } /* * options * * This routine handles the command line options. * For our simple /dev/Null, we support: * -v verbose operation */ void options (int argc, char **argv) { int opt; int i; optv = 0; i = 0; while (optind < argc) { while ((opt = getopt (argc, argv, "v")) != -1) { switch (opt) { case 'v': optv = 1; break; } } } } /* * io_read * * At this point, the client has called their library "read" * function, and expects zero or more bytes. Since this is * the /dev/Null resource manager, we return zero bytes to * indicate EOF -- no more bytes expected. */ int io_read (resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb) { int status; static char *data = "echo"; if (optv) { printf ("%s: in io_read\n", progname); } if ((status = iofunc_read_verify(ctp, msg, ocb, NULL)) != EOK) return status; /* No special xtypes */ if (msg->i.xtype & _IO_XTYPE_MASK != _IO_XTYPE_NONE) { return ENOSYS; } sleep(4); _IO_SET_READ_NBYTES (ctp, strlen(data)+1); if (msg->i.nbytes > 0) ocb->attr->flags |= IOFUNC_ATTR_ATIME; return _RESMGR_PTR (ctp, data, (strlen(data)+1)); } /* * io_write * * At this point, the client has called their library "write" * function, and expects that our resource manager will write * the number of bytes that they have specified to some device. * * Since this is /dev/Null, all of the clients writes always * work -- they just go into Deep Outer Space. */ int io_write (resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *ocb) { int status; char *buf; if (optv) { printf ("%s: in io_write\n", progname); } if ((status = iofunc_write_verify(ctp, msg, ocb, NULL)) != EOK) return status; /* No special xtypes */ if (msg->i.xtype & _IO_XTYPE_MASK != _IO_XTYPE_NONE) { return ENOSYS; } _IO_SET_WRITE_NBYTES (ctp, msg -> i.nbytes); buf = (char *) malloc(msg -> i.nbytes + 1); if (buf == NULL) return ENOMEM; resmgr_msgread(ctp, buf, msg -> i.nbytes, sizeof(msg -> i)); buf [msg -> i.nbytes] = '\0'; /* just in case */ printf ("%s: Received %d bytes = '%s'\n", progname, msg -> i.nbytes, buf); free(buf); if (msg->i.nbytes > 0) ocb->attr->flags |= IOFUNC_ATTR_MTIME | IOFUNC_ATTR_CTIME; return _RESMGR_NPARTS (0); }