/* 
 * Internet Back Plane Client code ibp_client.c 
 * 
 * First cut, May 1998. 
 * 
 * Wael R. Elwasif 
 * Computer Science Dept. 
 * University of Tennessee, Knoxville 
 * elwasif@cs.utk.edu 
 * 
 */ 

# include "ibp_protocol.h" 
# include "ibp_client.h" 

char *getLocalHostName(){ 

   struct utsname       localHost; 
   struct hostent       *he; 
   static char          *localHostName = NULL; 
  
   if (localHostName != NULL) 
      return localHostName; 
  
   if (uname(&localHost) == -1){ 
      fprintf(stderr,"Error: getLocalHostName(): uname()"); 
      return NULL; 
   } 

   he = gethostbyname(localHost.nodename); 
   if(he == NULL){ 
      fprintf(stderr,"Error: getLocalHostName(): gethostbyname()"); 
      return NULL; 
   } 

   he = gethostbyaddr(he->h_addr, he->h_length, he->h_addrtype); 
   if(he == NULL){ 
      fprintf(stderr,"Error: getLocalHostName(): gethostbyaddr()"); 
      return NULL; 
   } 

   localHostName = strdup(he->h_name); 
   return localHostName; 
} 
  


IBP_capability_set 
   IBP_allocate(char *targetHost, int size, IBP_attributes attr){ 
  
   int                  fd;                        /* File descriptor */ 
   char                 buf[100]; 
   IBP_capability_set   newCap; 
   int                  response; 
   int                  length; 
   char                 *localHostName; 
   int                  cmd; 
  
   localHostName = getLocalHostName();  /* Calls to get full local host name */ 
   if (localHostName == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_allocate(): getLocalHostName()\n"); 
      return NULL; 
   } 
  
   IBP_errno = IBP_OK; 
   if (targetHost == NULL){ 
      fprintf(stderr,"Error: IBP_allocate(): targetHost = NULL\n"); 
      return NULL; 
   } 
  
   fd = request_connection(targetHost, IBP_PORT);    /* Connect to server */ 
   if (fd == -1){ 
      IBP_errno = IBP_CONNECTION_ERROR; 
      fprintf(stderr,"Error: IBP_allocate(): error connecting to %s\n", 
               targetHost); 
      return NULL; 
   } 

   cmd = IBP_ALLOCATE; 
   if (IBP_write_int(fd, &cmd) == -1){          /* Send allocate request */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return NULL; 
   } 
  
   if( IBP_write_int(fd, &size) == -1){         /* Send byteArray size */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return NULL; 
   } 

   if( IBP_write_attrib(fd, attr) == -1){       /* Send byteArray attributes */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return NULL; 
   } 
  
   length = strlen(localHostName) + 1; 
   if( IBP_write_int(fd, &length) == -1){         /* Send local host name  */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return NULL; 
   } 
   if (IBP_write_chars(fd, localHostName, length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return NULL; 
   } 

   if(IBP_read_int(fd, &response) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return NULL; 
   } 

   if (response == IBP_OK){ 
      newCap = (IBP_capability_set) malloc(sizeof(struct ibp_capability_set)); 
      if ((newCap->readCap = IBP_read_cap(fd)) == NULL ){ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
         free(newCap); 
         close(fd); 
         return NULL; 
      } 
      if ((newCap->writeCap = IBP_read_cap(fd)) == NULL ){ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
         free(newCap->readCap); 
         free(newCap); 
         close(fd); 
         return NULL; 
      } 
   } 
   else{ 
      newCap = NULL; 
      IBP_errno = response; 
   } 
  
   close(fd); 
   return newCap; 
} 


int IBP_store(IBP_capability cap, char *data, int size){ 

   int   fd; 
   int   response; 
   int   length; 
   int   cmd; 
   char  *localHostName; 
   char  capBuf[MAX_CAP_LEN]; 
   char  *server; 
   char  *key; 
   char  *writeTag; 
  
   IBP_errno = IBP_OK; 

   localHostName = getLocalHostName();  /* Calls to get full local host name */ 
   if (localHostName == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_allocate(): getLocalHostName()\n"); 
      return -1; 
   } 
   strcpy(capBuf, cap); 
   writeTag = strstr(capBuf, "/WRITE"); 
   server = strtok(capBuf, "/");          /* Extract server name */ 
   key = strtok(NULL, "/"); 

   if ((server == NULL) || (key == NULL)){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_store(): Invalid capability format\n"); 
      return -1; 
   } 
   if (writeTag == NULL){ 
      IBP_errno = IBP_CAP_NOT_WRITE; 
      fprintf(stderr,"Error: IBP_store(): Invalid capability type\n"); 
      return -1; 
   } 
  
   fd = request_connection(server, IBP_PORT); /* Connect to server */ 
   if (fd == -1){ 
      IBP_errno = IBP_CONNECTION_ERROR; 
      return -1; 
   } 
  
   cmd = IBP_STORE; 
   if (IBP_write_int(fd, &cmd) == -1){             /* Send store request */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   length = strlen(key)+1; 
   if (IBP_write_int(fd, &length) == -1){          /* Send key length */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_write_chars(fd, key, length) == -1){    /* Send actual key */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_write_int(fd, &size) == -1){            /* Send data size */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   length = strlen(localHostName) + 1; 
   if (IBP_write_int(fd, &length) == -1){          /* Send key length */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_write_chars(fd, localHostName, length) == -1){ /* send client name */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   if (IBP_read_int(fd, &response) == -1){         /* Request parameters OK? */ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
      close(fd); 
      return -1; 
   } 
   if (response != IBP_OK){ 
      IBP_errno = response; 
      close(fd); 
      return(-1); 
   } 
  
   if (IBP_write(fd, data, size) == -1){           /* Send actual data */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_read_int(fd, &response) == -1){         /* Data transfer OK? */ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
      close(fd); 
      return -1; 
   } 

   close(fd); 
   if (response != IBP_OK){ 
      IBP_errno = response; 
      return (-1); 
   } 
   return 0; 
} 


int IBP_copy(IBP_capability source, IBP_capability target){ 

   int   fd_src; 
   int   response; 
   int   length; 
   int   cmd; 
   char  *localHostName; 
   char  capBuf[MAX_CAP_LEN]; 
   char  *server; 
   char  *key; 
   char  *readTag; 
  
   IBP_errno = IBP_OK; 

   localHostName = getLocalHostName();  /* Calls to get full local host name */ 
   if (localHostName == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_copy(): getLocalHostName()\n"); 
      return -1; 
   } 
   strcpy(capBuf, source); 
   readTag = strstr(capBuf, "/READ"); 
   server = strtok(capBuf, "/");             /* Extract source server name */ 
   key = strtok(NULL, "/"); 
  
   if ((server == NULL) || (key == NULL)){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_copy(): Invalid capability format\n"); 
      return -1; 
   } 
   if (readTag == NULL){ 
      IBP_errno = IBP_CAP_NOT_READ; 
      fprintf(stderr,"Error: IBP_copy(): Invalid capability type\n"); 
      return -1; 
   } 

   fd_src = request_connection(server, IBP_PORT); 
   if (fd_src == -1){ 
      IBP_errno = IBP_CONNECTION_ERROR; 
      return -1; 
   } 
  
   cmd = IBP_SEND; 
   if (IBP_write_int(fd_src, &cmd) == -1 ){      /* Send send request */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 
  
   length = strlen(key) + 1;                    /* Send source key */ 
   if (IBP_write_int(fd_src, &length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 

   if (IBP_write_chars(fd_src, key, length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 

   length = strlen(localHostName) + 1;                /* Send client name */ 
   if (IBP_write_int(fd_src, &length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 

   if (IBP_write_chars(fd_src, localHostName, length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 

   if (IBP_write_cap(fd_src, target) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 
  
   if (IBP_read_int(fd_src, &response) == -1){ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
      close(fd_src); 
      return -1; 
   } 
  
   close(fd_src); 
   if (response != IBP_OK){ 
      IBP_errno = response; 
      return (-1); 
   } 
  
   return 0; 
} 


int IBP_deliver(IBP_capability source, char *targetHost, int port){ 

   int   fd_src; 
   int   response1; 
   int   length; 
   int   cmd; 
   char  *localHostName; 
   char  capBuf[MAX_CAP_LEN]; 
   char  *server; 
   char  *key; 
   char  *readTag; 
  
   IBP_errno = IBP_OK; 

   localHostName = getLocalHostName();  /* Calls to get full local host name */ 
   if (localHostName == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_copy(): getLocalHostName()\n"); 
      return -1; 
   } 
  
   strcpy(capBuf, source); 
   readTag = strstr(capBuf, "/READ"); 
   server = strtok(capBuf, "/");             /* Extract source server name */ 
   key = strtok(NULL, "/"); 
   if ((server == NULL) || (key == NULL)){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_deliver(): Invalid capability format\n"); 
      return -1; 
   } 
   if (readTag == NULL){ 
      IBP_errno = IBP_CAP_NOT_READ; 
      fprintf(stderr,"Error: IBP_deliver(): Invalid capability type\n"); 
      return -1; 
   } 
  
   IBP_errno = IBP_OK; 
   fd_src = request_connection(server, IBP_PORT); 
   if (fd_src == -1){ 
      IBP_errno = IBP_CONNECTION_ERROR; 
      return -1; 
   } 
  
   cmd = IBP_DELIVER; 
   if (IBP_write_int(fd_src, &cmd) == -1 ){        /* Send deliver request */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 
  
   length = strlen(key)+1; 
   if (IBP_write_int(fd_src, &length) == -1){      /* Send source key length */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 

   if (IBP_write_chars(fd_src, key, length) == -1){    /* Send actual key */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 

   length = strlen(localHostName) + 1; 
   if (IBP_write_int(fd_src, &length) == -1){     /* Send client name length */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 

   if (IBP_write_chars(fd_src, localHostName, length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
    } 

   length = strlen(targetHost) + 1; 
   if (IBP_write_int(fd_src, &length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 
  
   if (IBP_write_chars(fd_src, targetHost, length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 

   if (IBP_write_int(fd_src, &port) == -1){           /* target port num. */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd_src); 
      return -1; 
   } 
  
   if (IBP_read_int(fd_src, &response1) == -1){ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
      close(fd_src); 
      return -1; 
   } 
  
   close(fd_src); 
   if (response1 != IBP_OK) { 
      IBP_errno = response1; 
      return (-1); 
   } 
   return 0; 
} 


int   IBP_increment(IBP_capability  cap){ 

   int   fd; 
   int   response; 
   int   length; 
   int   cmd; 
   char  *localHostName; 
   char  capBuf[MAX_CAP_LEN]; 
   char  *server; 
   char  *key; 
   char  *readTag; 
   char  *writeTag; 
   int   capType; 
  
   IBP_errno = IBP_OK; 

   localHostName = getLocalHostName();  /* Calls to get full local host name */ 
   if (localHostName == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_increment(): getLocalHostName()\n"); 
      return -1; 
   } 
  
   strcpy(capBuf, cap); 
   readTag = strstr(capBuf, "/READ"); 
   writeTag = strstr(capBuf, "/WRITE"); 
   server = strtok(capBuf, "/");             /* Extract source server name */ 
   key = strtok(NULL, "/"); 
   if (server == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_increment(): Invalid capability format\n"); 
      return -1; 
   } 
   if (readTag != NULL) 
      capType = IBP_READCAP; 
   else if (writeTag != NULL) 
      capType = IBP_WRITECAP; 
   else{ 
      IBP_errno = IBP_CAP_NOT_READ; 
      fprintf(stderr,"Error: IBP_increment(): Invalid capability type\n"); 
      return -1; 
   } 
  
   fd = request_connection(server, IBP_PORT);      /* Connect to server */ 
   if (fd == -1){ 
      IBP_errno = IBP_CONNECTION_ERROR; 
      return -1; 
   } 
  
   cmd = IBP_INCR; 
   if (IBP_write_int(fd, &cmd) == -1){          /* Send increment request */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   length = strlen(key) + 1; 
   if (IBP_write_int(fd, &length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   if (IBP_write_chars(fd, key, length) == -1){    /* send key */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   if (IBP_write_int(fd, &capType) == -1){         /* Send capability type */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

  
   length = strlen(localHostName) + 1; 
   if (IBP_write_int(fd, &length) == -1){          /* Send client name length */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_write_chars(fd, localHostName, length) == -1){ /* send client name */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_read_int(fd, &response) == -1){ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (response != IBP_OK){ 
      IBP_errno = response; 
      close(fd); 
      return (-1); 
   } 
  
   close(fd); 
   return 0; 
} 


int   IBP_decrement(IBP_capability  cap){ 
   int   fd; 
   int   response; 
   int   length; 
   int   cmd; 
   int   capType; 
   char  *localHostName; 
   char  capBuf[MAX_CAP_LEN]; 
   char  *server; 
   char  *key; 
   char  *readTag; 
   char  *writeTag; 
  
   IBP_errno = IBP_OK; 

   localHostName = getLocalHostName();  /* Calls to get full local host name */ 
   if (localHostName == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_decrement(): getLocalHostName()\n"); 
      return -1; 
   } 
  
   strcpy(capBuf, cap); 
   readTag = strstr(capBuf, "/READ"); 
   writeTag = strstr(capBuf, "/WRITE"); 
   server = strtok(capBuf, "/");             /* Extract source server name */ 
   key = strtok(NULL, "/"); 
   if (server == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_decrement(): Invalid capability format\n"); 
      return -1; 
   } 
   if (readTag != NULL) 
      capType = IBP_READCAP; 
   else if (writeTag != NULL) 
      capType = IBP_WRITECAP; 
   else{ 
      IBP_errno = IBP_CAP_NOT_READ; 
      fprintf(stderr,"Error: IBP_decrement(): Invalid capability type\n"); 
      return -1; 
   } 
  
   fd = request_connection(server, IBP_PORT);      /* Connect to server */ 
   if (fd == -1){ 
      IBP_errno = IBP_CONNECTION_ERROR; 
      return -1; 
   } 
  
   cmd = IBP_DECR; 
   if (IBP_write_int(fd, &cmd) == -1){          /* Send increment request */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   length = strlen(key) + 1; 
   if (IBP_write_int(fd, &length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
   if (IBP_write_chars(fd, key, length) == -1){    /* send key */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   if (IBP_write_int(fd, &capType) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
   length = strlen(localHostName) + 1; 
   if (IBP_write_int(fd, &length) == -1){          /* Send client name length */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_write_chars(fd, localHostName, length) == -1){ /* send client name */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_read_int(fd, &response) == -1){ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (response != IBP_OK){ 
      IBP_errno = response; 
      close(fd); 
      return -1; 
   } 
  
   close(fd); 
   return 0; 

} 


int IBP_probe(IBP_capability cap){ 
   int   fd; 
   int   response; 
   int   length; 
   int   state; 
   int   cmd; 
   char  capBuf[MAX_CAP_LEN]; 
   char  *localHostName; 
   char  *server; 
   char  *key; 
   char  *readTag; 
   char  *writeTag; 
   int   capType; 
  
   IBP_errno = IBP_OK; 
   localHostName = getLocalHostName();  /* Calls to get full local host name */ 
   if (localHostName == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_probe(): getLocalHostName()\n"); 
      return -1; 
   } 
  
   strcpy(capBuf, cap); 
   readTag = strstr(capBuf, "/READ"); 
   writeTag = strstr(capBuf, "/WRITE"); 
   server = strtok(capBuf, "/");             /* Extract source server name */ 
   key = strtok(NULL, "/"); 
   if (server == NULL){ 
      IBP_errno = IBP_ERROR; 
      fprintf(stderr,"Error: IBP_decrement(): Invalid capability format\n"); 
      return -1; 
   } 
   if (readTag != NULL) 
      capType = IBP_READCAP; 
   else if (writeTag != NULL) 
      capType = IBP_WRITECAP; 
   else{ 
      IBP_errno = IBP_CAP_NOT_READ; 
      fprintf(stderr,"Error: IBP_decrement(): Invalid capability type\n"); 
      return -1; 
   } 

   fd = request_connection(server, IBP_PORT);      /* Connect to server */ 
   if (fd == -1){ 
      IBP_errno = IBP_CONNECTION_ERROR; 
      return -1; 
   } 
  
   cmd = IBP_PROBE; 
   if (IBP_write_int(fd, &cmd) == -1){              /* Send probe request */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   length = strlen(key) + 1; 
   if (IBP_write_int(fd, &length) == -1){ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
   if (IBP_write_chars(fd, key, length) == -1){    /* send key */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
   if (IBP_write_int(fd, &capType) == -1){         /* send capability type */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   length = strlen(localHostName) + 1; 
   if (IBP_write_int(fd, &length) == -1){          /* Send client name length */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (IBP_write_chars(fd, localHostName, length) == -1){ /* send client name */ 
      IBP_errno = IBP_SOCK_WRITE_ERROR; 
      close(fd); 
      return -1; 
   } 
  
   if (IBP_read_int(fd, &response) == -1){ 
      IBP_errno = IBP_SOCK_READ_ERROR; 
      close(fd); 
      return -1; 
   } 

   if (response != IBP_OK){ 
      IBP_errno = response; 
      close(fd); 
      return (-1); 
   } 
  
   close(fd); 
   return -1s; 
} 
  
