/*
 * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
 * (Royal Institute of Technology, Stockholm, Sweden).
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the Kungliga Tekniska
 *      Högskolan and its contributors.
 * 
 * 4. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Test to talk with FS
 */

#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atypes.h>
#include <fs.h>
#include <fs.cs.h>
#include <time.h>
#include <lock.h>
#include <ip.h>
#include <krb.h>
#include <des.h>
#include <rxkad.h>
#include <list.h>
#include <config.h>

#include "service.h"
#include "ports.h"
#include "vldb.h"
#include <cb.h>
#include <cb.ss.h>

RCSID("$Id: dumbclient.c,v 1.15 1999/01/16 18:33:46 map Exp $") ;

#define AFSNAMEMAX 256

int benchloops = 10;
int filesize = 1024*1024;

#define BENCHLOOPS benchloops
#define FILESIZE filesize

#ifndef MAXPATHLEN
#define MAXPATHLEN 1024 /* XXX */
#endif

struct foobench {
    char name[MAXPATHLEN];
    AFSFid fid;
};

int verbose = 0;

/*
 * Try to read an AFS-file into local storage
 */

void skipline(char **curptr)
{
  while(**curptr!='\n') (*curptr)++;
  (*curptr)++;
}


int
getacl(struct rx_connection *rxConnP, AFSFid *fid)
{
    AFSOpaque opaque ;
    AFSFetchStatus dirNewStat ;
    AFSVolSync volSync ;
    int i, error ;
    int pos,neg;
    char *curptr;
    char tmpname[101];
    int tmprights;

    printf("trying to get acl\n");

    error = RXAFS_FetchACL(rxConnP, fid, &opaque, &dirNewStat, &volSync) ;
    if (error) {
	fprintf(stderr, "FetchACL failed with: %d\n", error);
	return;
    }
    printf("done..\n");
    curptr = opaque.val ;

#if 0
    for (i = 0 ; i < opaque.len;i++) {
	printf("%02x", curptr[i]);
	if(i%5==4) printf("\n");
    }
    printf("\n\n");
#endif

    if (sscanf(curptr, "%d\n%d\n", &pos, &neg) != 2) {
	printf("Internal getacl error\n");
	return;
    }

    skipline(&curptr);
    skipline(&curptr);

    while(pos) {
	sscanf(curptr, "%100s %d", tmpname, &tmprights);
	printf("%s %d\n", tmpname, tmprights);
	--pos;
	skipline(&curptr);
    }

    while(neg) {
	sscanf(curptr, "%100s %d", tmpname, &tmprights);
	printf("%s %d\n", tmpname, tmprights);
	--neg;
	skipline(&curptr);
    }

    free(opaque.val);
}

int
fillfid(struct rx_connection *rxConnP, AFSFid *fid, 
	size_t off, size_t size, void *mem)
{
    int ret, i;
    u_int32_t sizefs;
    char dummy[1024];
    AFSFetchStatus status;
    AFSCallBack callback;
    AFSVolSync volsync;
    struct rx_call *call;
    AFSStoreStatus ss;

    ss.Mask = 0;

    call = rx_NewCall (rxConnP);

    if (StartRXAFS_StoreData(call, fid, &ss, off, size, size) !=0) {
	fprintf(stderr, "StoreData\n");
	return;
    }

    if (verbose)
	printf("StartRXAFS_StoreData done\n");

    if (rx_Write(call, mem, size) != size) {
	printf("rx_Write failed\n");
	return;
    } 
	 
    ret = rx_EndCall (call, EndRXAFS_StoreData (call, &status,
						&callback,
						&volsync));
	 
    if (verbose)
	printf("EndCall: ret: %d\n", ret);
    return ret;
}



int
readfid(struct rx_connection *rxConnP, AFSFid *fid)
{
    int ret, i;
    u_int32_t sizefs;
    char dummy[1024*5];
    AFSFetchStatus status;
    AFSCallBack callback;
    AFSVolSync volsync;
    struct rx_call *call;

    call = rx_NewCall (rxConnP);

    /* msb is signed bit */
    if (StartRXAFS_FetchData(call, fid, 0, 0x7fffffff) !=0) {
	fprintf(stderr, "FetchData\n");
	return;
    }

    if (verbose)
	printf("StartRXAFS_FetchData done\n");

    ret = rx_Read (call, &sizefs, sizeof(sizefs));
    if (ret != sizeof(sizefs)) {
	printf("Error reading length\n");
	return;
    }
    sizefs = ntohl (sizefs);

    if (verbose)
	printf("Data length is: %d\n", sizefs);
	 
    while (sizefs > 0) {
	if (sizefs < sizeof(dummy)) 
	    i = sizefs; 
	else
	    i = sizeof(dummy);

	if (rx_Read(call, dummy, i) != i) {
	    printf("rx_Read failed\n");
	    return;
	} 
	sizefs -= i;
    }

    ret = rx_EndCall (call, EndRXAFS_FetchData (call, &status,
						&callback,
						&volsync));
	 
    if (verbose)
	printf("EndCall: ret: %d\n", ret);
}

int
createfile(struct rx_connection *rxConnP, AFSFid *dfid, 
	   char *name, AFSFid *fid)
{
    int ret, i;
    u_int32_t sizefs;
    char dummy[1024];
    AFSStoreStatus ss;
    AFSFetchStatus fs;
    AFSFetchStatus dfs;
    AFSCallBack callback;
    AFSVolSync volsync;

    ss.Mask = 0;
    
    if (ret = RXAFS_CreateFile(rxConnP,
			       dfid,
			       name, 
			       &ss,
			       fid,
			       &fs,
			       &dfs,
			       &callback,
			       &volsync)) {
	fprintf(stderr, "CreateFile %d\n", ret);
	return;
    }

    if (verbose)
	printf("CreateFile: %d\n", ret);
}

int
removefile(struct rx_connection *rxConnP, AFSFid *fid, 
	   char *name)
{
    int ret;
    AFSFetchStatus status;
    AFSVolSync volsync;

    ret = RXAFS_RemoveFile (rxConnP,
			    fid,
			    name,
			    &status,
			    &volsync);

    if (verbose)
	printf("RXAFS_RemoveFile: %d\n", ret);
    return ret;
}



void talk (char *host, CREDENTIALS *c, AFSFid *rfid) 
{
     struct rx_connection *rxConnP;
     struct rx_securityClass *secureobj[3]; 
     struct in_addr server;
     u_long hostIPAddr;
     int udpPort;
     unsigned long sec, usec;
     int port;
     int error;
     int secureindex ; 

     printf("Talking to afsserver %s\n", host);

     secureobj[0] = NULL ;
     secureobj[1] = NULL ;
     secureobj[2] = NULL ;

     if (ipgetaddr (host, &server) == NULL ) {
	  fprintf (stderr, "Cannot lookup %s\n", host);
	  return;
     }

     port = 7000 ;
     /*     port = 7003 ; */
     
     printf ("Connecting to FS on '%s', port %d, servid %d\n", host,
	     port, FS_SERVICE_ID);
#if 1
     secureobj[0] = rxnull_NewClientSecurityObject() ;
     secureindex = 0 ;
#else

#if 1
     rxkad_min_level = 2 ;
#endif     

     secureobj[2] = rxkad_NewClientSecurityObject(rxkad_auth,
						  &c->session,
						  c->kvno,
						  c->ticket_st.length,
						  c->ticket_st.dat);
     secureindex = 2 ;

#endif

     rxConnP = rx_NewConnection (server.s_addr, 
				 htons (port), 
				 /* VLDB_SERVICE_ID,  */
				 FS_SERVICE_ID, 
				 secureobj[secureindex],
				 secureindex);

     if (rxConnP == NULL) {
	 fprintf (stderr, "Cannot start rx-connection\n");
	 return;
     }

#if 0
	 readacl(rxConnP, rfid);
#endif     

#if 1
     {
	 int i;
	 struct timeval start, stop;
	 long long start_l, stop_l;
	 AFSFid pfid = *rfid;
	 void *mem ;
	 struct foobench *arr;

         mem = calloc(FILESIZE, sizeof(char));
	 arr = calloc(BENCHLOOPS, sizeof(struct foobench));

	 printf("Performance test: %d files, %d bytes each\n",
		BENCHLOOPS, FILESIZE);
	 printf("Creating names\n");
	 fflush(stdout);

	 for (i = 0; i < BENCHLOOPS; i++)
	     snprintf(arr[i].name, MAXPATHLEN, "testname%d", i);

	 printf("Creating files\n"); fflush(stdout);
	 gettimeofday(&start, NULL);
	 for (i = 0; i < BENCHLOOPS; i++)
	     createfile(rxConnP, &pfid, arr[i].name, &arr[i].fid);
	 gettimeofday(&stop, NULL);
	 start_l = start.tv_sec * 1000000 + start.tv_usec;
	 stop_l = stop.tv_sec * 1000000 + stop.tv_usec;
	 printf("Creating files: %llu msec\n", (stop_l-start_l)/1000);

	 printf("Writing\n"); fflush(stdout);
	 gettimeofday(&start, NULL);
	 for (i = 0; i < BENCHLOOPS; i++)
	     fillfid(rxConnP, &arr[i].fid, 0, FILESIZE,mem);
	 gettimeofday(&stop, NULL);
	 start_l = start.tv_sec * 1000000 + start.tv_usec;
	 stop_l = stop.tv_sec * 1000000 + stop.tv_usec;
	 printf("Writing files %llu msec\n", (stop_l-start_l)/1000);

	 printf("Reading\n"); fflush(stdout);
	 gettimeofday(&start, NULL);
	 for (i = 0; i < BENCHLOOPS; i++)
	     readfid(rxConnP, &arr[i].fid);
	 gettimeofday(&stop, NULL);
	 start_l = start.tv_sec * 1000000 + start.tv_usec;
	 stop_l = stop.tv_sec * 1000000 + stop.tv_usec;
	 printf("Reading file: %llu msec\n", (stop_l-start_l)/1000);

	 printf("Removing\n"); fflush(stdout);
	 gettimeofday(&start, NULL);
	 for (i = 0; i < BENCHLOOPS; i++)
	     removefile(rxConnP, &pfid, arr[i].name);
	 gettimeofday(&stop, NULL);
	 start_l = start.tv_sec * 1000000 + start.tv_usec;
	 stop_l = stop.tv_sec * 1000000 + stop.tv_usec;
	 printf("Removing file %llu msec\n", (stop_l-start_l)/1000);

	 free(mem);
	 free(arr);
     }
#endif

#if 0
     {     
	 /* insert security check */
	 AFSFid pfid = *rfid;
	 void *mem ;
	 char name[MAXPATHLEN] = "foobarXXXXXXXXX";
	 AFSFid fid;

	 createfile(rxConnP, &pfid, name, &fid);
	 name[6] = '\n';
	 fillfid(rxConnP, &fid, 0, 7, name);
	 fillfid(rxConnP, &fid, 4711, 7, name);
     }
#endif


#if 0
     printf("Trying to get time\n");

     error = RXAFS_GetTime (rxConnP, &sec, &usec);
     if (error) {
	  fprintf (stderr, "GetTime, error = %d\n", error);
	  return;
     }
	  
     printf ("Server %s time is %s\n", host, ctime (&sec));
#endif
	  
#if 0
     printf("Trying VL_probe\n");
     error = VL_Probe (rxConnP);
     if (error) {
	  fprintf (stderr, "Can't even probe: error = %d\n", error);
	  return;
     }
     printf("Probe succesful\n");
#endif

     rx_Finalize ();
}

void initrx ()
{
     int error;

}


static int
get_cred(const char *princ, const char *inst, const char *krealm, 
         CREDENTIALS *c)
{
  KTEXT_ST foo;
  int k_errno;

  k_errno = krb_get_cred((char*)princ, (char*)inst, (char*)krealm, c);

  if(k_errno != KSUCCESS) {
    k_errno = krb_mk_req(&foo, (char*)princ, (char*)inst, (char*)krealm, 0);
    if (k_errno == KSUCCESS)
      k_errno = krb_get_cred((char*)princ, (char*)inst, (char*)krealm, c);
  }
  return k_errno;
}


void
cmcb_init (void)
{
     static struct rx_securityClass *nullSecObjP;
     static struct rx_securityClass *(securityObjects[1]);

     nullSecObjP = rxnull_NewClientSecurityObject ();
     if (nullSecObjP == NULL) {
	  printf("Cannot create null security object.\n");
	  return;
     }
     
     securityObjects[0] = nullSecObjP;

     if (rx_NewService (0, CM_SERVICE_ID, "cm", securityObjects,
			sizeof(securityObjects) / sizeof(*securityObjects),
			(long (*)())RXAFSCB_ExecuteRequest) == NULL ) {
	  printf("Cannot install service.\n");
	  return;
     }
     rx_StartServer (0);
}

int
RXAFSCB_Probe (struct rx_call *a_rxCallP)
{
     printf("CB_Probe\n");
     return 0;
}

int
RXAFSCB_InitCallBackState (struct rx_call *a_rxCallP)
{
     printf("CB_InitCallBackState\n");
     return 0;
}

int
RXAFSCB_CallBack (struct rx_call *a_rxCallP,
		  const AFSCBFids *a_fidArrayP,
		  const AFSCBs *a_callBackArrayP)
{
     printf("CB_Callback\n");
     return 0;
}

int
getfid(int argc, char **argv, AFSFid *fid)
{
    argc--; argv++; 
    if (argc)
	sscanf(*argv, "%d", &fid->Volume);
    else
	return 0;
    argc--; argv++; 
    if (argc)  
	sscanf(*argv, "%d", &fid->Vnode);
    else
	return 00;
    argc--; argv++; 
    if (argc)  
	sscanf(*argv, "%d", &fid->Unique);
    else
	return 0;
    argc--; argv++; 
    if (argc)  
	sscanf(*argv, "%d", &filesize);
    else
	return 0;
    argc--; argv++; 
    if (argc)  
	sscanf(*argv, "%d", &benchloops);
    else
	return 0;
    return argc;
}

int main (int argc, char **argv)
{
     char buf[256];
     int error;
     CREDENTIALS c ;
     char *hostname;
     AFSFid fid = { 1, 1, 1};
     
     argc--;
     argv++;

     if (argc)
	 hostname = *argv;
     else
	 hostname = "pike.pdc.kth.se";

     getfid(argc, argv, &fid);
     
     error = rx_Init (htons(4711));
     if (error) {
	  fprintf (stderr, "Cannot rx_init. code = %d\n", error);
	  return;
     }

     if (get_cred("afs","pdc.kth.se","NADA.KTH.SE", &c)) {
	 printf("error getting ticket, yiips\n") ;
     } 

     printf("CB_Init\n");
     cmcb_init();
     
     talk(hostname, &c, &fid) ;

     return 0;
}
