death-to-permit-xprt-h-20010327
[openafs.git] / src / rx / test / generator.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * generator.c -- phase 2 of the generator.
12  *
13  * takes a file, which has a list of signature as input,
14  * and outputs the client, server, .xg, and makefiles
15  * This file is normally created by running tableGen.c,
16  * but theoretically could be generated by a human.
17  *
18  * Format of the signatures : no_of_args list_of_arg_signs
19  *  arg_sign : (dir type)
20  *
21  *
22  * This program is used to generate client/server pairs that
23  * make and verify random rpcs.  It can be used to generate
24  * both pthread and lwp versions of the client and server.
25  * It was designed to verify that the new pthread rx library
26  * was functioning correctly.
27  *
28  * The key to understanding how this program works is to realize
29  * that all the data necessary to generate the client/server
30  * code is generated first, in char string format.
31  * For example, if you are generating 10 rpc's, the input and
32  * output values of all the parameters are generated - and
33  * stored as strings.  This allows you to write out the values
34  * as the client and server are created without having to worry
35  * about data type conversion.
36  *
37  * In addition, these strings (along with other information) are
38  * stored in a structure that is iterated over many times during
39  * the construction of the client and server.
40  *
41  * Often this iteration takes the form of:
42  *     for (i=0; i < argsP->argCount; i++)
43  *
44  * It may be possible to eliminate some of these iterations for
45  * efficiency sake, but this was not done - allowing an easier
46  * implementation.
47  *
48  * The bulk of this code was lifted from the delight project.
49  *
50  */
51
52 #include <stdio.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include <limits.h>
56 #include <float.h>
57 #include <malloc.h>
58 #include <assert.h>
59 #include "generator.h"
60
61 static char *unix_symbols[] = {
62     "make -f",
63     "include ../../../config/Makefile.$(SYS_NAME)\n",
64     "o",
65     "$(CC) $(CFLAGS) -c",
66     "#include <netdb.h>\n",
67     "",
68
69 /* all one string */
70     "LIBS = $(DESTDIR)lib/libafsrpc.so \\\n"
71     "\t$(DESTDIR)lib/afs/libcmd.a \\\n"
72     "\t$(DESTDIR)lib/afs/libcom_err.a \\\n"
73     "\t$(DESTDIR)lib/afs/util.a \n",
74
75 /* all one string */
76     "LIBS = $(DESTDIR)lib/librxkad.a \\\n"
77     "\t$(DESTDIR)lib/libdes.a \\\n"
78     "\t$(DESTDIR)lib/librx.a \\\n"
79     "\t$(DESTDIR)lib/liblwp.a \\\n"
80     "\t$(DESTDIR)lib/afs/libcmd.a \\\n"
81     "\t$(DESTDIR)lib/afs/libcom_err.a \\\n"
82     "\t$(DESTDIR)lib/afs/util.a \\\n"
83     "\t/usr/ucblib/libucb.a \n",
84
85 /* all one string */
86     "\t@if [ ! -r DEST ] ; \\\n"
87     "\tthen \\\n"
88     "\t\techo \"Must create DEST link by hand before building tests\"; \\\n"
89     "\t\texit 1; \\\n"
90     "\tfi\n"
91 };
92
93 static char *nt_symbols[] = {
94     "nmake /f",
95     "!INCLUDE ../../../config/NTMakefile.$(SYS_NAME)\n",
96     "obj",
97     "$(C2OBJ)",
98     "#include <windows.h>\n",
99     "all",
100
101 /* all one string */
102     "LIBS = $(DESTDIR)/lib/afsrpc.lib \\\n"
103     "\t$(DESTDIR)/lib/afs/afscmd.lib \\\n"
104     "\t$(DESTDIR)/lib/afs/afscom_err.lib \\\n"
105     "\t$(DESTDIR)/lib/afs/afsutil.lib \\\n"
106     "\t$(DESTDIR)/lib/pthread.lib \\\n"
107     "\t$(DESTDIR)/lib/afsreg.lib \\\n"
108     "\t$(XLIBS)\n",
109
110 /* all one string */
111     "LIBS = $(DESTDIR)/lib/afsrxkad.lib \\\n"
112     "\t$(DESTDIR)/lib/afsdes.lib \\\n"
113     "\t$(DESTDIR)/lib/afsrx.lib \\\n"
114     "\t$(DESTDIR)/lib/afslwp.lib \\\n"
115     "\t$(DESTDIR)/lib/afs/afscmd.lib \\\n"
116     "\t$(DESTDIR)/lib/afs/afscom_err.lib \\\n"
117     "\t$(DESTDIR)/lib/afs/afsutil.lib \\\n"
118     "\t$(DESTDIR)/lib/afsreg.lib \n",
119
120 /* all one string */
121     "!\tIF (!EXIST(DEST))\n"
122     "!\t\tERROR Must create DEST link by hand before building tests\n"
123     "!\tENDIF\n",
124 };
125
126 static char **platform = nt_symbols;
127
128 #if defined(WIN32)
129 #define strdup(x)               _strdup(x)
130 #endif /* WIN32 */
131
132 /*
133  * 31 bit random number generator, we don't really care how random
134  * these numbers are, it is more important that identical rx files
135  * are generated no matter what platform the generator runs on
136  */
137 static unsigned long randVal = 0x330E16;
138
139 typedef enum {
140    PTHREADS,
141    LWPS
142 } threadModel_t;
143
144 static threadModel_t threadModel = PTHREADS;
145
146 PRIVATE double drand32(void)
147 {
148     randVal = ((randVal * 0xEECE66D) + 0xB) & 0xFFFFFFFF;
149     return ((double)(randVal) / 4294967296.0);
150 }
151
152 /*
153  * GetDescription writes a one line comment describing the parameters
154  * used in an rpc in the client program
155  */
156 PRIVATE char *GetDescription(rpcArgs *argsP)
157 {
158     char *bufP2;
159     int i;
160
161     bufP2 = (char *) calloc((MAX_TYP_STR+MAX_DIR_STR+ATTRIB_LEN*ATTRIB_NO)
162                     *argsP->argCount+3, sizeof(char));
163     MEM_CHK(bufP2, "GetDescription: out of mem bufP2\n");
164
165     for (i=0; i < argsP->argCount; i++) {
166         strcat(bufP2, argsP->argDescr[i].direction);
167         strcat(bufP2, argsP->argDescr[i].type);
168     }
169     return(bufP2);
170 }
171
172 /*
173  * GetName -- get the name of the current server/instance
174  */
175 PRIVATE char *GetName(char *serverName, int sign_no)
176 {
177     /* itl file name 8.3 format*/
178     char *bufP;
179
180     bufP = (char *) malloc(32 * sizeof(char));
181     MEM_CHK(bufP, "GetName: bufP out of mem\n");
182
183     sprintf(bufP, "%s%d", serverName, sign_no);
184     return bufP;
185 }
186
187 /*
188  * OpenOutFile -- open a file in the output directory
189  */
190 PRIVATE FILE *OpenOutFile(char *outDir, char *fileName, char *tailStr)
191 {
192     char *bufP;
193     FILE *fP;
194
195     if (outDir) {
196         bufP = (char *) malloc(sizeof(char)*(strlen(fileName)+
197                             strlen(tailStr)+strlen(outDir)+2));
198         MEM_CHK(bufP, "OpenOutFile : Out of mem -- bufP\n");
199         sprintf(bufP, "%s/%s%s", outDir, fileName, tailStr);
200     } else {
201         bufP = (char *) malloc(sizeof(char)*(strlen(fileName)+
202                             strlen(tailStr)+1));
203         MEM_CHK(bufP, "OpenOutFile : Out of mem -- bufP\n");
204         sprintf(bufP, "%s%s", fileName, tailStr);
205     }
206     fP = fopen(bufP, "w");
207     MEM_CHK(fP, "main: Unable to open output file\n");
208     free(bufP);
209     return (fP);
210 }
211
212 /*
213  * WriteXGDecl -- write the declaration for a parameter
214  */
215 PRIVATE void WriteXGDecl(arg_tuple *arg, FILE *xg_h, int i, 
216                           int structFlag, int lastFlag)
217 {
218     if (structFlag) {
219         if (!strcmp(arg->type, "varString")) {
220             fprintf(xg_h, "\tchar a%d[STR_MAX];\n", i);
221         }
222         else {
223             fprintf(xg_h, "\tdrpc_%s_t a%d;\n", arg->type, i);
224         }
225     } else {
226         if (!strncmp(arg->type, "ar_", 2)) {
227             fprintf(xg_h, "\t%s drpc_out_%s_t *a%d",
228                     arg->direction, arg->type, i);
229         }
230         else if (!strcmp(arg->type, "varString")) {
231             fprintf(xg_h, "\t%s string a%d<STR_MAX>",
232                     arg->direction, i);
233         }
234         else if (!strcmp(arg->direction, "IN")) {
235             fprintf(xg_h, "\t%s drpc_%s_t a%d",
236                     arg->direction, arg->type, i);
237         } else {
238             fprintf(xg_h, "\t%s drpc_%s_t *a%d",
239                     arg->direction, arg->type, i);
240         }
241         if (lastFlag) {
242             fputs(");\n", xg_h);
243         } else {
244             fputs(",\n", xg_h);
245         }
246     }
247 }
248
249 /*
250  * WriteXG -- write the body of the xg interface
251  */
252 PRIVATE void WriteXG(rpcArgs *argsP, FILE *xg_h, char *serverName, int sign_no)
253 {
254     int i;
255     char *name = GetName(serverName, sign_no);
256
257     /*
258      * CASE 1: all arguments passed as parameters
259      */
260
261     fprintf(xg_h, "\nproc %s(\n", name);
262
263     /* declare each arg */
264     for (i=0; i < argsP->argCount; i++) {
265         WriteXGDecl(&argsP->argDescr[i], xg_h, i, FALSE,
266                      (i==argsP->argCount-1));
267     }
268
269     /* Now pass the paramaters inside a structure */
270     fprintf(xg_h, "\nstruct %s_t {\n", name);
271     for (i=0; i < argsP->argCount; i++) {
272         WriteXGDecl(&argsP->argDescr[i], xg_h, i, TRUE,
273                      (i==argsP->argCount-1));
274     }
275     fprintf(xg_h, "} ;\n");
276     fprintf(xg_h, "\nproc %s_s(\n", name);
277     fprintf(xg_h, "\tINOUT struct %s_t *s);\n", name);
278
279     free(name);
280 }
281
282 /*
283  * GetRandStr -- get a random string
284  */
285 PRIVATE void GetRandStr(int strLen, char **ret, int *rP)
286 {
287     int i, randI;
288     char buf[5];
289
290     strcpy(*ret, "\"");
291     i = 0;
292     while (i < strLen) {
293         randI = 'A' + ('Z' - 'A')*drand32();
294         sprintf(buf, "%c", randI);
295         strcat(*ret, buf);
296         i++;
297     }
298     strcat(*ret, "\"");
299     *rP = randI;
300 }
301
302 /*
303  * GetRandP -- sets a string to a random value of the data type
304  * inthe case of a char type, ret holds "%c" and ret2 holds '%c'
305  */
306 PRIVATE void GetRandP(char *typ, char **ret, char **ret2)
307 {
308     int randI, strLen;
309     float f;
310     double d, d1;
311     short shI;
312
313     *ret = (char *) calloc(MAX_RAND_LENGTH+1, sizeof(char));
314     *ret2 = (char *) calloc(MAX_RAND_LENGTH+1, sizeof(char));
315
316     if (strstr(typ, "char")) {
317         GetRandStr(1, ret2, &randI);
318         if (randI == '\\')
319             strcpy(*ret2, "'\\\\'");
320         else if(randI == '\'')
321             strcpy(*ret2, "'\\''");
322         else
323             sprintf(*ret, "'%c'", randI);
324             return;
325     } else if (strstr(typ, "short")) {
326         shI = SHRT_MIN + (SHRT_MAX - SHRT_MIN) * drand32();
327         sprintf(*ret, "%d", shI);
328         strcpy(*ret2, *ret);
329     } else if (strstr(typ, "afs_int32")) {
330         randI = INT_MIN + UINT_MAX * drand32();
331         if (randI < INT_MIN || randI > INT_MAX) {
332             fprintf(stderr, "GetRandP: afs_int32 %d out of bounds\n", randI);
333             exit(1);
334         }
335         sprintf(*ret, "%d", randI);
336         strcpy(*ret2, *ret);
337     } else if (strstr(typ, "float")) {
338         d = drand32();
339         f = d;
340         sprintf(*ret, "%2.8e", f);
341         strcpy(*ret2, *ret);
342
343     } else if (strstr(typ, "double")) {
344         d1 = drand32();
345         sprintf(*ret, "%2.16e", d1);
346         strcpy(*ret2, *ret);
347
348     } else if (strstr(typ, "String")) {
349         strLen = (MAX_RAND_LENGTH-2)*drand32();
350         GetRandStr(strLen, ret, &randI);
351         strcpy(*ret2, *ret);
352     }
353 }
354
355
356 /*
357  * GenParamValues -- generate the parameter values for an rpc
358  */
359 PRIVATE void GenParamValues(rpcArgs *argsP)
360 {
361     char *typ;
362     int i, j;
363
364     /* generate random values for each argument */
365     for (i=0; i < argsP->argCount; i++) {
366
367         argsP->argDescr[i].vc_low = 0;
368         argsP->argDescr[i].vc_max = IDL_FIX_ARRAY_SIZE-1;
369         argsP->argDescr[i].vc_high = IDL_FIX_ARRAY_SIZE-1;
370         argsP->argDescr[i].ovc_low = 0;
371         argsP->argDescr[i].ovc_high = IDL_FIX_ARRAY_SIZE-1;
372
373         if (!strncmp(argsP->argDescr[i].type, "ar_", 3)) {
374             typ = argsP->argDescr[i].type + 3;
375             for (j = 0 ; j < IDL_FIX_ARRAY_SIZE ; j++) {
376                 GetRandP(typ, &argsP->argDescr[i].inValue[j],
377                          &argsP->argDescr[i].inValue2[j]);
378                 GetRandP(typ, &argsP->argDescr[i].outValue[j],
379                          &argsP->argDescr[i].outValue2[j]);
380             }
381         } else {
382             GetRandP(argsP->argDescr[i].type,
383                      &argsP->argDescr[i].inValue[0],
384                      &argsP->argDescr[i].inValue2[0]);
385             GetRandP(argsP->argDescr[i].type,
386                      &argsP->argDescr[i].outValue[0],
387                      &argsP->argDescr[i].outValue2[0]);
388         }
389     }
390 }
391
392 /*
393  * WriteServC -- write the rpcs in the server file
394  */
395 PRIVATE void WriteServC(rpcArgs *argsP, FILE *srv_h, char *serverName, int sign_no)
396 {
397     char *name, *typ;
398     int i,j;
399
400     name = GetName(serverName, sign_no);
401     fprintf(srv_h, "\nint A%s(struct rx_call *c,\n", name);
402
403     /* declare each arg */
404     for (i=0; i < argsP->argCount; i++) {
405
406         if (!strcmp(argsP->argDescr[i].type, "varString")) {
407             if (!strcmp(argsP->argDescr[i].direction, "IN")) {
408                 fprintf(srv_h, "\tchar *a%d", i);
409             }
410             else {
411                 fprintf(srv_h, "\tchar **a%d", i);
412             }
413         }
414         else if (strncmp(argsP->argDescr[i].type, "ar_", 3) &&
415                 (!strcmp(argsP->argDescr[i].direction, "IN"))) {
416             fprintf(srv_h, "\tdrpc_%s_t a%d", argsP->argDescr[i].type, i);
417         } else {
418             if (!strncmp(argsP->argDescr[i].type, "ar_", 3)) {
419                 fprintf(srv_h, "\tdrpc_out_%s_t *a%d", argsP->argDescr[i].type, i);
420             }
421             else {
422                 fprintf(srv_h, "\tdrpc_%s_t *a%d", argsP->argDescr[i].type, i);
423             }
424         }
425         if(i < (argsP->argCount - 1)) {
426             fprintf(srv_h, ",\n");
427         }
428     }
429     fputs(")\n{\n", srv_h); /* balance the } */
430     fputs("\tint errFlag = 0;", srv_h);
431
432     /*
433      * check the in and inout parameters
434      */
435     for (i=0; i < argsP->argCount; i++) {
436
437         if (!strcmp(argsP->argDescr[i].direction, "IN") ||
438                    (!strcmp(argsP->argDescr[i].direction, "INOUT") &&
439                     !strcmp(argsP->argDescr[i].type, "varString"))) {
440
441             typ = argsP->argDescr[i].type;
442
443             if (strstr(typ, "String")) {
444                 if(!strcmp(argsP->argDescr[i].direction, "INOUT")) {
445                     fprintf(srv_h, "\n\tCHECK%s((char *)*a%d, %s, \"%s\");",
446                             typ, i, argsP->argDescr[i].inValue[0], name);
447                 } else {
448                     fprintf(srv_h, "\n\tCHECK%s((char *)a%d, %s, \"%s\");",
449                             typ, i, argsP->argDescr[i].inValue[0], name);
450                 }
451             } else if (!strcmp(typ, "afs_int32")) {
452                 fprintf(srv_h, "\n\tCHECK%s(a%d, %sL, \"%s\");",
453                         typ, i, argsP->argDescr[i].inValue[0], name);
454             } else {
455                 if(!strncmp(typ, "ar_", 3)) {
456                     for(j=0;j<IDL_FIX_ARRAY_SIZE;j++)
457                         fprintf(srv_h, "\n\tCHECK%s(a%d->drpc_out_%s_t_val[%d], %s, \"%s\");",
458                                 (typ+3), i, typ, j, argsP->argDescr[i].inValue[j],
459                                 name);
460                 }
461                 else {
462                     fprintf(srv_h, "\n\tCHECK%s(a%d, %s, \"%s\");",
463                             typ, i, argsP->argDescr[i].inValue[0], name);
464                 }
465             }
466         } else if (!strcmp(argsP->argDescr[i].direction, "INOUT")) {
467
468             typ = argsP->argDescr[i].type;
469
470             if (strstr(typ, "String")) {
471                 fprintf(srv_h, "\n\tCHECK%s((char *)*a%d, %s, \"%s\");",
472                         typ, i, argsP->argDescr[i].inValue[0], name);
473             } else if (!strcmp(typ, "afs_int32")) {
474                 fprintf(srv_h, "\n\tCHECK%s(*a%d, %sL, \"%s\");",
475                         typ, i, argsP->argDescr[i].inValue[0], name);
476             } else {
477                 if(!strncmp(typ, "ar_", 3)) {
478                     for(j=0;j<IDL_FIX_ARRAY_SIZE;j++)
479                         fprintf(srv_h, "\n\tCHECK%s(a%d->drpc_out_%s_t_val[%d], %s, \"%s\");",
480                                 (typ+3), i, typ, j, argsP->argDescr[i].inValue[j],
481                                 name);
482                 }
483                 else {
484                     fprintf(srv_h, "\n\tCHECK%s(*a%d, %s, \"%s\");",
485                             typ, i, argsP->argDescr[i].inValue[0], name);
486                 }
487             }
488         }
489     }
490
491     /*
492      * free up memory for dynamic input args
493      */
494     for (i=0; i < argsP->argCount; i++) {
495         if (!strncmp(argsP->argDescr[i].type, "ar_", 3)) {
496             typ = argsP->argDescr[i].type;
497             if(!strcmp(argsP->argDescr[i].direction, "INOUT")) {
498                 fprintf(srv_h, "\n\tif (a%d->drpc_out_%s_t_val) "
499                         "free(a%d->drpc_out_%s_t_val);", i, typ, i, typ);
500             }
501             if(!strcmp(argsP->argDescr[i].direction, "INOUT") ||
502                !strcmp(argsP->argDescr[i].direction, "OUT")) {
503                 fprintf(srv_h, "\n\ta%d->drpc_out_%s_t_val = (%s *) "
504                         "malloc(FIX_ARRAY_SIZE * sizeof(%s));",
505                         i, typ, (typ+3), (typ+3));
506                 fprintf(srv_h, "\n\ta%d->drpc_out_%s_t_len = FIX_ARRAY_SIZE;",
507                         i, typ);
508             }
509         }
510     }
511
512     /*
513      * set the inout and out parameters
514      */
515     for (i=0; i < argsP->argCount; i++) {
516
517         if (!strcmp(argsP->argDescr[i].direction, "INOUT") ||
518                    !strcmp(argsP->argDescr[i].direction, "OUT")) {
519
520             typ = argsP->argDescr[i].type;
521
522             if (!strncmp(typ, "ar_", 3)) {
523                 for(j=0;j<IDL_FIX_ARRAY_SIZE;j++)
524                     fprintf(srv_h, "\n\ta%d->drpc_out_%s_t_val[%d] = %s;",
525                             i, typ, j, argsP->argDescr[i].outValue[j]);
526             } else if (!strcmp(typ, "afs_int32")) {
527                 fprintf(srv_h, "\n\t*a%d = %sL;",
528                         i, argsP->argDescr[i].outValue[0]);
529             } else if (!strcmp(typ, "varString")) {
530                 if(!strcmp(argsP->argDescr[i].direction, "OUT")) {
531                     fprintf(srv_h, "\n\t*a%d = (char *) malloc(STR_MAX);", i);
532                 }
533                 fprintf(srv_h, "\n\tstrcpy((char *)*a%d, %s);",
534                         i, argsP->argDescr[i].outValue[0]);
535             } else if (strstr(typ, "String")) {
536                 fprintf(srv_h,
537                         "\n\t*a%d = (drpc_%s_t)rpc_ss_allocate(%d);",
538                         i, typ, strlen(argsP->argDescr[i].outValue[0])-1);
539                 fprintf(srv_h, "\n\tstrcpy((char *)*a%d, %s);",
540                         i, argsP->argDescr[i].outValue[0]);
541             } else {
542                 fprintf(srv_h, "\n\t*a%d = %s;",
543                         i, argsP->argDescr[i].outValue[0]);
544             }
545         }
546     }
547
548     fprintf(srv_h,
549             "\n\tif (errFlag) {"
550             "\n\t\tprintf(\"%s: failed\\n\");"
551             "\n\t\tfflush(stdout);"
552             "\n\t}"
553             "\n\treturn errFlag;\n}\n",
554             name);
555
556     /*
557      * second routine with arguments inside a structure
558      */
559     fprintf(srv_h, "\nint A%s_s(struct rx_call *c,\n\t%s_t *s)\n{"
560                     "\n\tint errFlag = 0;", name, name);
561
562     /*
563      * check the in and inout parameters
564      */
565     for (i=0; i < argsP->argCount; i++) {
566
567         if (!strcmp(argsP->argDescr[i].direction, "IN") ||
568                    (!strstr(argsP->argDescr[i].type, "String") &&
569                     !strcmp(argsP->argDescr[i].direction, "INOUT"))) {
570
571             typ = argsP->argDescr[i].type;
572
573             if(!strncmp(typ, "ar_", 3)) {
574                 for(j=0;j<IDL_FIX_ARRAY_SIZE;j++)
575                     fprintf(srv_h, "\n\tCHECK%s(s->a%d[%d], %s, \"%s_s\");",
576                             (typ+3), i, j, argsP->argDescr[i].inValue[j],
577                             name);
578             }
579             else if (strstr(typ, "String")) {
580                 fprintf(srv_h, "\n\tCHECK%s((char *)s->a%d, %s, \"%s_s\");",
581                         typ, i, argsP->argDescr[i].inValue[0], name);
582             } else if (!strcmp(typ, "afs_int32")) {
583                 fprintf(srv_h, "\n\tCHECK%s(s->a%d, %sL, \"%s_s\");",
584                         typ, i, argsP->argDescr[i].inValue[0], name);
585             } else {
586                 fprintf(srv_h, "\n\tCHECK%s(s->a%d, %s, \"%s_s\");",
587                         typ, i, argsP->argDescr[i].inValue[0], name);
588             }
589         }
590     }
591
592     /*
593      * set the inout and out parameters
594      */
595     for (i=0; i < argsP->argCount; i++) {
596
597         if (!strcmp(argsP->argDescr[i].direction, "INOUT") ||
598                    !strcmp(argsP->argDescr[i].direction, "OUT")) {
599
600             typ = argsP->argDescr[i].type;
601
602             if(!strncmp(typ, "ar_", 3)) {
603                 for(j=0;j<IDL_FIX_ARRAY_SIZE;j++)
604                     fprintf(srv_h, "\n\ts->a%d[%d]= %s;",
605                             i, j, argsP->argDescr[i].outValue[j]);
606             }
607             else if (!strcmp(typ, "afs_int32")) {
608                 fprintf(srv_h, "\n\ts->a%d = %sL;",
609                         i, argsP->argDescr[i].outValue[0]);
610             } else if (!strcmp(typ, "varString")) {
611                 fprintf(srv_h, "\n\tstrcpy((char *)s->a%d, %s);",
612                         i, argsP->argDescr[i].outValue[0]);
613             } else if (strstr(typ, "String")) {
614                 fprintf(srv_h, "\n\ts->a%d = rpc_ss_allocate(%d);",
615                         i, strlen(argsP->argDescr[i].outValue[0])-1);
616                 fprintf(srv_h, "\n\tstrcpy((char *)s->a%d, %s);",
617                         i, argsP->argDescr[i].outValue[0]);
618             } else {
619                 fprintf(srv_h, "\n\ts->a%d = %s;",
620                         i, argsP->argDescr[i].outValue[0]);
621             }
622         }
623     }
624
625     fprintf(srv_h,
626             "\n\tif (errFlag) {"
627             "\n\t\tprintf(\"%s_s: failed\\n\");"
628             "\n\t}"
629             "\n\tfflush(stdout);"
630             "\n\treturn errFlag;\n}\n",
631             name);
632
633
634     free(name);
635 }
636
637 /*
638  * WriteMake - write the makefile for a particular client/server pair
639  */
640 PRIVATE void WriteMake(char *serverName, int srv_no, FILE *mak_h)
641 {
642     char p[1024];
643     char *obj=platform[2];
644
645     sprintf(p,"%s%d", serverName, srv_no);
646     fprintf(mak_h, "%s", platform[1]);
647     if (threadModel == PTHREADS) {
648         fprintf(mak_h, 
649                 "CFLAGS = -KPIC -g -mt -I$(DESTDIR)include\n"
650                 "%s",
651                 platform[6]
652                 );
653     } else {
654         fprintf(mak_h, 
655                 "CFLAGS = -g -I$(DESTDIR)include\n"
656                 "%s",
657                 platform[7]
658                 );
659     }
660     fprintf(mak_h,
661             "\n\ntest: all\ntests: all\nall: %sClt %sSrv\n\n"
662             "%sClt: %s.cs.%s %s.xdr.%s %sClt.%s $(LIBS)\n",
663             p,p,p,p,obj,p,obj,p,obj
664             );
665     if(platform == nt_symbols) {
666         fprintf(mak_h, "\t$(EXECONLINK)\n\n");
667     } else {
668         fprintf(mak_h,
669                 "\t$(CC) $(CFLAGS) -o $@ %sClt.%s %s.cs.%s %s.xdr.%s "
670                 "$(LIBS) $(XLIBS)\n\n",
671                 p,obj,p,obj,p,obj
672                 );
673     }
674     fprintf(mak_h,
675             "%s.xdr.c: %s.xg\n\n"
676             "%s.h %s.cs.c %s.ss.c: %s.xg\n"
677             "\t$(RXGEN) %s.xg\n"
678             "\t%s %s.cs.c\n"
679             "\t%s %s.ss.c\n\n",
680             p,p,p,p,p,p,p,platform[3],p,platform[3],p);
681     fprintf(mak_h,
682             "%sSrv: %s.ss.%s %s.xdr.%s %sSrv.%s $(LIBS)\n",
683             p,p,obj,p,obj,p,obj);
684
685     if(platform == nt_symbols) {
686         fprintf(mak_h, "\t$(EXECONLINK)\n\n");
687     } else {
688         fprintf(mak_h,
689                 "\t$(CC) $(CFLAGS) -o $@ %sSrv.o %s.ss.o %s.xdr.o "
690                 "$(LIBS) $(XLIBS)\n\n",
691                 p,p,p
692                 );
693     }
694
695     if(platform == unix_symbols) {
696         fprintf(mak_h,
697                 "clean:\n"
698                 "\t/bin/rm -f %sClt %s.h %s.cs.c %s.ss.c core "
699                 "%sSrv %sSrv.o \\\n"
700                 "\t%sClt.o %s.cs.o %s.ss.o %s.xdr.c %s.xdr.o\n",
701                 p,p,p,p,p,p,p,p,p,p,p);
702     }
703
704 }
705
706 /*
707  * WriteCltTrailer - finish writing client source
708  */
709 PRIVATE void WriteCltTrailer(char *serverName, int first, int last, FILE *itl_h)
710 {
711     int i=0;
712
713     /*
714      * Write out 1 function that calls all the manager functions
715      */
716     if (threadModel == PTHREADS) {
717         fprintf(itl_h, "\n\nvoid *threadFunc(void *arg) {\n");
718     } else {
719         fprintf(itl_h, "\n\nint threadFunc(int *arg) {\n");
720     }
721
722     fprintf(itl_h, 
723             "\tstruct rx_connection *conn;\n"
724             "\tint error=0;\n\n"
725             "\tint i = (int) arg;\n\n"
726             );
727
728     fprintf(itl_h, "\tconn = rx_GetCachedConnection(serverAddr,serverPort,4,secClass,secIndex);\n");
729
730     fprintf(itl_h, "\twhile(i--) {\n");
731
732     if (first == 0) first = 1;
733     for(i=first;i<last;i++) {
734         fprintf(itl_h, "\t\tC_%s%d(conn);\n",serverName, i);
735         fprintf(itl_h, "\t\tC_%s%d_s(conn);\n",serverName, i);
736     }
737     fprintf(itl_h, "\t}\n");
738
739     fprintf(itl_h, "\trx_ReleaseCachedConnection(conn);\n");
740
741     if (threadModel == PTHREADS) {
742         fprintf(itl_h, "\treturn (void *) 0;\n");
743     } else {
744         fprintf(itl_h, 
745             "\tLWP_CALL(LWP_SignalProcess,(&done));\n"
746             "\treturn 0;\n"
747             );
748     }
749
750     fprintf(itl_h, "}\n");
751
752     fprintf(itl_h,
753             "\n\nstatic void DoRun(struct cmd_syndesc *as, char *arock) {\n"
754             );
755
756     if (threadModel == PTHREADS) {
757         fprintf(itl_h, "\tpthread_t *tid;\n");
758     } else {
759         fprintf(itl_h, "\tPROCESS *tid;\n");
760     }
761     
762     fprintf(itl_h,
763             "\tint i,j;\n"
764             "\tunsigned int numThreads=0,numIterations=0;\n"
765             "\tint errflg=0;\n"
766             "\tstruct hostent *host=NULL;\n\n"
767             "\tnumThreads = atoi(as->parms[0].items->data);\n"
768             "\tnumIterations = atoi(as->parms[1].items->data);\n"
769             "\tsecType = atoi(as->parms[2].items->data);\n"
770             "\tencLevel = atoi(as->parms[3].items->data);\n"
771             "\tserverPort = htons(atoi(as->parms[4].items->data));\n"
772             "\tif ((host = hostutil_GetHostByName(as->parms[5].items->data))==0) {\n"
773             "\t\terrflg++;\n"
774             "\t}\n"
775             "\telse {\n"
776             "\t\tmemcpy((void *) &serverAddr, (const void *)host->h_addr, sizeof(serverAddr));\n"
777             "\t}\n"
778             "\tif ((secType<1) || (secType>2)) errflg++;\n"
779             "\tif ((encLevel<0) || (encLevel>2)) errflg++;\n"
780             "\tif ((serverPort == 0) ||(numThreads == 0) ||(numIterations == 0)) errflg++;\n"
781             "\tif (errflg) {\n"
782             "\t\tprintf(\"invalid argument\\n\");\n"
783             "\t\texit(1);\n"
784             "\t}\n\n"
785             "\tif(rx_Init(htons(0)) < 0) {\n"
786             "\t\texit(1);\n"
787             "\t}\n\n"
788             "\tswitch(secType) {\n"
789             "\t\tcase 1:\n"
790             "\t\t\tsecIndex = 0;\n"
791             "\t\t\tsecClass = rxnull_NewClientSecurityObject();\n"
792             "\t\t\tbreak;\n"
793             "\t\tcase 2:\n"
794             "\t\t\tif (GetTicket (&kvno, &Ksession, &ticketLen, ticket) == 0) {\n"
795             "\t\t\t\tsecIndex = 2;\n"
796             "\t\t\t\tsecClass = rxkad_NewClientSecurityObject(encLevel,\n"
797             "\t\t\t\t&Ksession, kvno, ticketLen, ticket);\n"
798             "\t\t\t}\n"
799             "\t\t\tbreak;\n"
800             "\t\tdefault:\n"
801             "\t\t\tbreak;\n"
802             "\t}\n"
803             "\tassert(secClass);\n\n"
804             );
805     if (threadModel == PTHREADS) {
806         fprintf(itl_h,
807                 "#if defined sun\n"
808                 "\tthr_setconcurrency(numThreads);\n"
809                 "#endif\n"
810                 "\ttid = (pthread_t *) "
811                 "malloc(numThreads*(sizeof(pthread_t)));\n"
812                 );
813     } else {
814         fprintf(itl_h,
815                 "\ttid = (PROCESS *) malloc(numThreads*(sizeof(PROCESS *)));\n"
816                 );
817     }
818
819     fprintf(itl_h,
820             "\tassert(tid);\n"
821             "\tfor(j=0;j<numThreads;j++) {\n"
822             );
823     if (threadModel == PTHREADS) {
824         fprintf(itl_h,
825                 "\t\ti = pthread_create(&tid[j], (const pthread_attr_t *) 0,\n"
826                 "\t\tthreadFunc, (void *) numIterations);\n"
827                 "\t\tassert(i==0);\n"
828                 );
829     } else {
830         fprintf(itl_h,
831                 "\t\tLWP_CALL(LWP_CreateProcess,(threadFunc, 10*4096, LWP_NORMAL_PRIORITY, numIterations, \"foo\", &tid[j]));\n"
832                 );
833     }
834
835     fprintf(itl_h,
836             "\t}\n"
837             "\tfor(j=0;j<numThreads;j++) {\n"
838             );
839     if (threadModel == PTHREADS) {
840         fprintf(itl_h, 
841                 "\t\ti = pthread_join(tid[j], (void **) 0);\n"
842                 "\t\tassert(i==0);\n"
843                 );
844     } else {
845         fprintf(itl_h, "\t\tLWP_CALL(LWP_WaitProcess,(&done));\n");
846     }
847     fprintf(itl_h,
848             "\t}\n"
849             "\trx_Finalize();\n"
850             "\tfree(tid);\n"
851             "}\n"
852             );
853
854     /*
855      * Write command syntax function
856      */
857
858     fprintf(itl_h,
859             "static void SetupRunCmd(void) {\n"
860             "\tstruct cmd_syndesc *ts;\n"
861             "\tts = cmd_CreateSyntax((char *) 0,DoRun, 0, \"run the test client program\");\n"
862             "\tcmd_AddParm(ts, \"-threadCount\", CMD_SINGLE, CMD_REQUIRED, \"number of threads to spawn\");\n"
863             "\tcmd_AddParm(ts, \"-iterationCount\", CMD_SINGLE, CMD_REQUIRED, \"number of iterations to make over entire interface for each thread\");\n"
864             "\tcmd_AddParm(ts, \"-secType\", CMD_SINGLE, CMD_REQUIRED, \"security level to use (1 -> unauthenticated, 2 -> authenticated)\");\n"
865             "\tcmd_AddParm(ts, \"-encLevel\", CMD_SINGLE, CMD_REQUIRED, \"encryption level to use, (0-> rxkad_clear, 1 -> rxkad_auth, 2 -> rxkad_crypt)\");\n"
866             "\tcmd_AddParm(ts, \"-serverPort\", CMD_SINGLE, CMD_REQUIRED, \"port that server is using\");\n"
867             "\tcmd_AddParm(ts, \"-serverHost\", CMD_SINGLE, CMD_REQUIRED, \"host where server is running\");\n"
868             "}\n"
869             );
870
871     /*
872      * Write client main
873      */
874
875     fprintf(itl_h,
876             "int main (int argc, char *argv[]) {\n"
877             "\tint code;\n\n"
878             "\tinitialize_cmd_error_table();\n"
879             "\tSetupRunCmd();\n"
880             "\tcode = cmd_Dispatch(argc, argv);\n\n"
881             "\treturn(code);\n"
882             "\t}\n"
883             );
884
885 }
886
887 /*
888  * Create macros useful for checking input/output parameters
889  */
890
891 PRIVATE void WriteTestMacros(FILE *f) {
892     fprintf(f,
893         "\n#define CHECKchar(x,y,z) if ((x)!=(y)) { printf(\"%%s: Got '%%c',"
894         "expected '%%c'\\n\", z, (char)x, (char)(y)); fflush(stdout); "
895         "errFlag = 1; } "
896         "\n#define CHECKshort(x,y,z) if ((x)!=(y)) "
897         "{ printf(\"%%s: Got 0x%%04x, "
898         "expected 0x%%04x\\n\", z, x, y); fflush(stdout); "
899         "errFlag = 1; } "
900         "\n#define CHECKint32(x,y,z) if ((x)!=(y)) "
901         "{ printf(\"%%s: Got 0x%%08x, "
902         "expected 0x%%08x\\n\", z, x, y); fflush(stdout); "
903         "errFlag = 1; } "
904         "\n#define CHECKfloat(x,y,z) if (((x)/(y)<.999999) "
905         "|| ((x)/(y)>1.000001)) "
906         "{ printf(\"%%s: Got %%2.8e, expected %%2.8e\\n\", z, x, y); "
907         "fflush(stdout); "
908         "errFlag = 1; } "
909         "\n#define CHECKdouble(x,y,z) if (((x)/(y)<.999999999999999) || "
910         "((x)/(y)>1.000000000000001)) { printf(\"%%s: Got %%2.16e, "
911         "expected %%2.16e\\n\", z, x, y); fflush(stdout); errFlag = 1; }"
912         "\n#define CHECKvarString(x,y,z) if (strcmp((x),(y))) { printf(\"%%s: "
913         "Got \\\"%%s\\\", expected \\\"%%s\\\"\\n\", z, x, y); fflush(stdout); "
914         "errFlag = 1; } \n");
915 }
916
917 /*
918  * WriteCltHeader - write the begining of the client code.
919  */
920 PRIVATE void WriteCltHeader(char *serverName, int srv_no, FILE *itl_h)
921 {
922     fprintf(itl_h, "#include <stdio.h>\n");
923     if (threadModel == PTHREADS) {
924             fprintf(itl_h,"#include <pthread.h>\n");
925     }
926     fprintf(itl_h,
927             "%s"
928             "#include <assert.h>\n"
929             "#include <rx/rx.h>\n"
930             "#include <rx/rx_null.h>\n"
931             "#include <rx/rxkad.h>\n"
932             "#include <afs/cmd.h>\n"
933             "#include \"%s%d.h\"\n"
934             ,
935             platform[4], serverName, srv_no);
936     if (threadModel == LWPS) {
937         fprintf(itl_h,
938             "\n\n#define LWP_CALL(fnName, params) \\\n"
939             "{ \\\n"
940             "\tint rc; \\\n"
941             "\trc = fnName params; \\\n"
942             "\tif (rc != LWP_SUCCESS) { \\\n"
943             "\t\tprintf(\"call to %%s failed with %%d\\n\", # fnName, rc); \\\n"
944             "\t\texit(1); \\\n"
945             "\t} \\\n"
946             "};\n\n"
947             "char done;\n\n");
948     }
949
950     fprintf(itl_h,
951             "struct ktc_encryptionKey serviceKey =\n"
952             "\t{0x45, 0xe3, 0x3d, 0x16, 0x29, 0x64, 0x8a, 0x8f};\n"
953             "long serviceKeyVersion = 7;\n"
954             "\nextern struct hostent *hostutil_GetHostByName();\n\n"
955             "static long GetTicket (long *versionP,\n"
956             "\tstruct ktc_encryptionKey *session,\n"
957             "\tint * ticketLenP, char *ticket)\n"
958             "{\n"
959             "\tlong code;\n"
960             "\tdes_init_random_number_generator (&serviceKey);\n"
961             "\tcode = des_random_key (session);\n"
962             "\tif (code) return code;\n"
963             "\t*ticketLenP = 0;\n"
964             "\tcode = tkt_MakeTicket(ticket, ticketLenP, &serviceKey,\n"
965             "\t\t\"tclnt\", \"\", \"\",\n"
966             "\t\t0, 0xffffffff, session, 0,\n"
967             "\t\t\"tsrvr\", \"\");\n"
968             "\tif (code) return code;\n"
969             "\t*versionP = serviceKeyVersion;\n"
970             "\treturn 0;\n"
971             "}\n\n"
972             "static int secType,encLevel,serverPort,serverAddr;\n"
973             "struct rx_securityClass *secClass;\n"
974             "int secIndex;\n"
975             "long kvno;\n"
976             "char ticket[MAXKTCTICKETLEN];\n"
977             "int ticketLen;\n"
978             "struct ktc_encryptionKey Ksession;\n\n"
979             );
980     WriteTestMacros(itl_h);
981
982 }
983
984 /*
985  * WriteCltInit -- write the initialization for each param
986  */
987 PRIVATE void WriteCltInit(arg_tuple *arg, FILE *itl_h, int i, 
988                           int structFlag)
989 {
990     int j;
991     char *s = (structFlag) ? "s." : "";
992
993     if ((!strncmp(arg->direction, "IN", 2) || structFlag)) {
994         if (!strncmp(arg->type, "varString", 9)) {
995             fprintf(itl_h, "\tstrcpy(%sa%d, %s);\n", s, i, arg->inValue[0]);
996         }
997         else if (!strncmp(arg->type, "ar_", 3)) {
998             if(!structFlag) {
999                 fprintf(itl_h, "\t%sa%d.drpc_out_%s_t_len = FIX_ARRAY_SIZE;\n",
1000                         s, i, arg->type);
1001                 fprintf(itl_h, 
1002                         "\t%sa%d.drpc_out_%s_t_val = "
1003                         "(%s *) malloc(FIX_ARRAY_SIZE * sizeof(%s));\n",
1004                         s, i, arg->type, (arg->type + 3), (arg->type + 3));
1005             }
1006             for(j=0;j<IDL_FIX_ARRAY_SIZE;j++) {
1007                 if(structFlag) {
1008                     fprintf(itl_h, 
1009                             "\t%sa%d[%d] = %s;\n",
1010                             s, i, j,arg->inValue[j]);
1011                 }
1012                 else {
1013                     fprintf(itl_h, 
1014                             "\t%sa%d.drpc_out_%s_t_val[%d] = %s;\n",
1015                             s, i, arg->type,j,arg->inValue[j]);
1016                 }
1017             }
1018         }
1019         else {
1020             fprintf(itl_h, "\t%sa%d = %s;\n", s, i, arg->inValue[0]);
1021         }
1022     }
1023 }
1024
1025 /*
1026  * WriteCltCall -- write each parameter for a call
1027  */
1028 PRIVATE void WriteCltCall(arg_tuple *arg, FILE *itl_h, int i) {
1029
1030     if (!strncmp(arg->type, "varString", 9)) {
1031         if ((!strncmp(arg->direction, "OUT", 3)) ||
1032             (!strncmp(arg->direction, "INOUT", 5))) {
1033             fprintf(itl_h, "&a%d_p", i);
1034         }
1035         else {
1036             fprintf(itl_h, "a%d_p", i);
1037         }
1038     }
1039     else {
1040         if ((!strncmp(arg->direction, "OUT", 3)) ||
1041             (!strncmp(arg->direction, "INOUT", 5)) || 
1042             (!strncmp(arg->type, "ar_", 3))) {
1043             fprintf(itl_h, "&a%d", i);
1044         }
1045         else {
1046             fprintf(itl_h, "a%d", i);
1047         }
1048     }
1049 }
1050
1051 /*
1052  * WriteCltDecl -- write the declaration for a parameter
1053  */
1054 PRIVATE void WriteCltDecl(arg_tuple *arg, FILE *itl_h, int i) {
1055
1056     if (!strncmp(arg->type, "ar_", 3)) {
1057         if (!strncmp(arg->direction, "OUT", 3)) {
1058             fprintf(itl_h, "\tdrpc_out_%s_t a%d = {0,0};\n", arg->type, i);
1059         }
1060         else {
1061             fprintf(itl_h, "\tdrpc_out_%s_t a%d;\n", arg->type, i);
1062         }
1063     }
1064     else if (!strncmp(arg->type, "varString", 9)) {
1065         fprintf(itl_h, "\tchar a%d[STR_MAX];\n", i);
1066         fprintf(itl_h, "\tchar *a%d_p = a%d;\n", i, i);
1067     }
1068     else {
1069         fprintf(itl_h, "\t%s a%d;\n", arg->type, i);
1070     }
1071 }
1072
1073
1074 /*
1075  * WriteClt -- write the rpcs in the client
1076  */
1077 PRIVATE void WriteClt(rpcArgs *argsP, char *serverName, int sign_no, FILE *itl_h)
1078 {
1079     char *name, *name2, *typ;
1080     int i,j;
1081
1082     name = GetName(serverName, sign_no);
1083     name2 = GetDescription(argsP);
1084
1085     fprintf(itl_h, "\n/* %s */\n\n", name2);
1086
1087     fprintf(itl_h, "\nvoid C_%s(struct rx_connection *conn) {\n", name);
1088
1089     /* declare each arg */
1090     for (i=0; i < argsP->argCount; i++) {
1091         WriteCltDecl(&argsP->argDescr[i], itl_h, i);
1092     }
1093     fprintf(itl_h, "\tint error;\n\tint errFlag;\n\n");
1094
1095     /* initialize IN/INOUT args */
1096     for (i=0; i < argsP->argCount; i++) {
1097         WriteCltInit(&argsP->argDescr[i], itl_h, i, FALSE);
1098     }
1099
1100     /* call the server */
1101     fprintf(itl_h, "\terror = A%s(conn, ", name);
1102
1103     /* pass each arg */
1104     for (i=0; i < argsP->argCount; i++) {
1105         WriteCltCall(&argsP->argDescr[i], itl_h, i);
1106         fprintf(itl_h, ((i < (argsP->argCount -1))) ? "," : ");\n");
1107     }
1108
1109     fprintf(itl_h, 
1110             "\tif (error != 0) {\n"
1111             "\t\tprintf(\"C_%s failed %%d\\n\", error);\n"
1112             "\t\tfflush(stdout);\n"
1113             "\t\treturn;\n"
1114             "\t}\n",
1115             name);
1116
1117     /*
1118      * check the in and inout parameters
1119      */
1120     for (i=0; i < argsP->argCount; i++) {
1121
1122         if ((!strcmp(argsP->argDescr[i].direction, "OUT")) ||
1123                     (!strcmp(argsP->argDescr[i].direction, "INOUT"))) {
1124
1125             typ = argsP->argDescr[i].type;
1126
1127             if(!strncmp(typ, "ar_", 3)) {
1128                 for(j=0;j<IDL_FIX_ARRAY_SIZE;j++)
1129                     fprintf(itl_h, "\n\tCHECK%s(a%d.drpc_out_%s_t_val[%d], %s, \"C_%s_s\");",
1130                             (typ+3), i, typ, j, argsP->argDescr[i].outValue[j],
1131                             name);
1132             }
1133             else if (strstr(typ, "String")) {
1134                 fprintf(itl_h, "\n\tCHECK%s((char *)a%d, %s, \"C_%s_s\");",
1135                         typ, i, argsP->argDescr[i].outValue[0], name);
1136             } else if (!strcmp(typ, "afs_int32")) {
1137                 fprintf(itl_h, "\n\tCHECK%s(a%d, %sL, \"C_%s_s\");",
1138                         typ, i, argsP->argDescr[i].outValue[0], name);
1139             } else {
1140                 fprintf(itl_h, "\n\tCHECK%s(a%d, %s, \"C_%s_s\");",
1141                         typ, i, argsP->argDescr[i].outValue[0], name);
1142             }
1143         }
1144     }
1145
1146     /*
1147      * free up memory for dynamic input args
1148      */
1149     for (i=0; i < argsP->argCount; i++) {
1150         if (!strncmp(argsP->argDescr[i].type, "ar_", 3)) {
1151             typ = argsP->argDescr[i].type;
1152             fprintf(itl_h, "\n\tif (a%d.drpc_out_%s_t_val) "
1153                     "free(a%d.drpc_out_%s_t_val);", i, typ, i, typ);
1154         }
1155     }
1156
1157
1158     fprintf(itl_h, "\n}\n");
1159
1160     /*
1161      * Call the structure oriented rpc interface
1162      */
1163
1164     fprintf(itl_h, "\nvoid C_%s_s(struct rx_connection *conn) {\n", name);
1165     fprintf(itl_h, "\tstruct %s_t s;\n", name);
1166     fprintf(itl_h, "\tint error;\n\tint errFlag;\n\n");
1167
1168     /* initialize IN/INOUT args */
1169     for (i=0; i < argsP->argCount; i++) {
1170         WriteCltInit(&argsP->argDescr[i], itl_h, i, TRUE);
1171     }
1172
1173     /* call the server */
1174     fprintf(itl_h, "\terror = A%s_s(conn, &s);\n", name);
1175
1176     fprintf(itl_h, 
1177             "\tif (error != 0) {\n"
1178             "\t\tprintf(\"C_%s_s failed %%d\\n\", error);\n"
1179             "\t\tfflush(stdout);\n"
1180             "\t\treturn;\n"
1181             "\t}\n",
1182             name);
1183
1184     /*
1185      * check the in and inout parameters
1186      */
1187     for (i=0; i < argsP->argCount; i++) {
1188
1189         if ((!strcmp(argsP->argDescr[i].direction, "OUT")) ||
1190                     (!strcmp(argsP->argDescr[i].direction, "INOUT"))) {
1191
1192             typ = argsP->argDescr[i].type;
1193
1194             if(!strncmp(typ, "ar_", 3)) {
1195                 for(j=0;j<IDL_FIX_ARRAY_SIZE;j++)
1196                     fprintf(itl_h, "\n\tCHECK%s(s.a%d[%d], %s, \"C_%s_s\");",
1197                             (typ+3), i, j, argsP->argDescr[i].outValue[j],
1198                             name);
1199             }
1200             else if (strstr(typ, "String")) {
1201                 fprintf(itl_h, "\n\tCHECK%s((char *)s.a%d, %s, \"C_%s_s\");",
1202                         typ, i, argsP->argDescr[i].outValue[0], name);
1203             } else if (!strcmp(typ, "afs_int32")) {
1204                 fprintf(itl_h, "\n\tCHECK%s(s.a%d, %sL, \"C_%s_s\");",
1205                         typ, i, argsP->argDescr[i].outValue[0], name);
1206             } else {
1207                 fprintf(itl_h, "\n\tCHECK%s(s.a%d, %s, \"C_%s_s\");",
1208                         typ, i, argsP->argDescr[i].outValue[0], name);
1209             }
1210         }
1211     }
1212
1213
1214     fprintf(itl_h, "\n}\n");
1215
1216     free(name);
1217     free(name2);
1218 }
1219
1220 /*
1221  * WriteXGHeader -- fill in Header info in the xg file
1222  */
1223 PRIVATE void WriteXGHeader(char *serverName, FILE *xg_h, int srv_no)
1224 {
1225
1226     /* create the interface header */
1227
1228     fprintf(xg_h,
1229             "\n/* Do not edit this file -- it was created by a generator */\n"
1230             "\npackage A\n\n"
1231             "const STR_MAX = %d; \n"
1232             "const FIX_ARRAY_SIZE = %d; \n"
1233             "typedef char drpc_char_t; \n"
1234             "typedef short drpc_short_t; \n"
1235             "typedef long drpc_int32_t; \n"
1236             "typedef string drpc_varString_t<STR_MAX>; \n"
1237             "typedef drpc_char_t drpc_ar_char_t[FIX_ARRAY_SIZE]; \n"
1238             "typedef drpc_char_t drpc_out_ar_char_t<FIX_ARRAY_SIZE>; \n"
1239             "typedef drpc_short_t drpc_ar_short_t[FIX_ARRAY_SIZE]; \n"
1240             "typedef drpc_short_t drpc_out_ar_short_t<FIX_ARRAY_SIZE>; \n"
1241             "typedef drpc_int32_t drpc_ar_int32_t[FIX_ARRAY_SIZE]; \n"
1242             "typedef drpc_int32_t drpc_out_ar_int32_t<FIX_ARRAY_SIZE>; \n"
1243             ,
1244             IDL_STR_MAX, IDL_FIX_ARRAY_SIZE);
1245 }
1246
1247 /*
1248  * WriteServHeader -- fill in the Header info in the server file
1249  */
1250 PRIVATE void WriteServHeader(FILE *srv_h, char *serverName, int srv_no)
1251 {
1252     char *name;
1253
1254     name = GetName(serverName, srv_no);
1255
1256     fprintf(srv_h,
1257         "\n/* Do not edit this file -- it's been created by a generator */\n\n" 
1258         "%s\n"
1259         "#include <stdio.h>\n"
1260         "#include <string.h>\n"
1261         "#include <stdlib.h>\n"
1262         "#include <rx/rx.h>\n"
1263         "#include <rx/rx_null.h>\n"
1264         "#include <rx/rxkad.h>\n"
1265         "#include <afs/cmd.h>\n"
1266         "#include \"%s.h\"\n\n"
1267         "struct ktc_encryptionKey serviceKey =\n"
1268         "\t{0x45, 0xe3, 0x3d, 0x16, 0x29, 0x64, 0x8a, 0x8f};\n"
1269         "long serviceKeyVersion = 7;\n\n"
1270         "extern int AExecuteRequest();\n"
1271         "extern char *optarg;\n"
1272         "extern int optind, opterr, optopt;\n\n"
1273         "#define VERIFY(x,y) if (!(x)) { printf y ; exit(1); }\n"
1274         "#define CHECK(x) ASSERT(x)\n"
1275         ,
1276         platform[4], name);
1277
1278     WriteTestMacros(srv_h);
1279     free(name);
1280 }
1281
1282 /*
1283  * WriteServTrailer -- finish up the server file
1284  */
1285 PRIVATE void WriteServTrailer(FILE *srv_h) {
1286
1287     fprintf(srv_h, 
1288             "\nstatic long GetKey (char *rock, long kvno, struct ktc_encryptionKey *key) {\n"
1289             "\tmemcpy ((void *) key, (void *) &serviceKey, sizeof(*key));\n"
1290             "\treturn 0;\n"
1291             "}\n\n"
1292
1293             "static void DoRun(struct cmd_syndesc *as, char *arock) {\n"
1294             "\tstruct rx_service *serv;\n"
1295             "\tstruct rx_securityClass *sc[3];\n\n"
1296             "\tint port=0, errflg=0;\n"
1297
1298             "\tint lowThreads=4, highThreads=8;\n"
1299             "\tlowThreads = atoi(as->parms[0].items->data);\n"
1300             "\thighThreads = atoi(as->parms[1].items->data);\n"
1301             "\tport = atoi(as->parms[2].items->data);\n"
1302
1303             "\tif (port == 0) errflg++;\n"
1304
1305             "\tif (errflg) {\n"
1306             "\t\tprintf(\"invalid argument\\n\");\n"
1307             "\t\texit(1);\n"
1308             "\t}\n"
1309
1310             "\trx_Init(htons(port));\n"
1311             "\tsc[0] = rxnull_NewServerSecurityObject();\n"
1312             "\tsc[1] = 0;\n"
1313             "\tsc[2] = rxkad_NewServerSecurityObject (rxkad_clear, 0, GetKey, 0);\n"
1314             "\tif (serv = rx_NewService(0,4,\"foo\",sc,3,AExecuteRequest)) {\n"
1315             "\t\trx_SetMinProcs(serv,lowThreads);\n"
1316             "\t\trx_SetMaxProcs(serv,highThreads);\n"
1317             "\t\trx_StartServer(1);\n"
1318             "\t}\n"
1319             "\texit(0);\n"
1320             "}\n\n"
1321
1322             "static void SetupRunCmd(void) {\n"
1323             "\tstruct cmd_syndesc *ts;\n"
1324             "\tts = cmd_CreateSyntax((char *) 0,DoRun, 0, \"run the test server program\");\n"
1325             "\tcmd_AddParm(ts, \"-lowThreadCount\", CMD_SINGLE, CMD_REQUIRED, \"minimum number of threads to spawn\");\n"
1326             "\tcmd_AddParm(ts, \"-highThreadCount\", CMD_SINGLE, CMD_REQUIRED, \"maximum number of threads to spawn\");\n"
1327             "\tcmd_AddParm(ts, \"-serverPort\", CMD_SINGLE, CMD_REQUIRED, \"port that server is using\");\n"
1328             "}\n"
1329
1330             "int main(int argc, char **argv) {\n"
1331             "\tint code;\n"
1332             "\tinitialize_cmd_error_table();\n"
1333             "\tSetupRunCmd();\n"
1334             "\tcode = cmd_Dispatch(argc, argv);\n"
1335             "\treturn(code);\n"
1336             "}\n"
1337             );
1338 }
1339
1340 /*
1341  * ProcessCmdLine -- processes the command line args
1342  */
1343 PRIVATE void ProcessCmdLine(int argc, char **argv,  char **serverName,
1344                             char **ipFileName,  char **outputDir)
1345 {
1346     if (argc == 1) {
1347         PrintShortUsage;
1348         exit(1);
1349     }
1350     /* command line processing */
1351     while (--argc > 0) {
1352         if ((*++argv)[0] == '-') {
1353             switch ((*argv)[1]) {
1354
1355                 case 'f':
1356                 case 'F':   /* input table file */
1357                     *ipFileName = *++argv;
1358                     --argc;
1359                     break;
1360                 case 'h': /* display help */
1361                 case 'H':
1362                     PrintLongUsage;
1363                     exit(0);
1364                     break;
1365                 case 'l':
1366                 case 'L':   /* use LWP threads */
1367                     threadModel = LWPS;
1368                     break;
1369                 case 's':
1370                 case 'S':   /* serverName */
1371                     *serverName = *++argv;
1372                     /* need 8 char file name, and so truncate the server name*/
1373                     if ((int)strlen(*serverName) > MAX_SERV_NAME)
1374                         *(*serverName+MAX_SERV_NAME) = '\0';            
1375                     --argc;
1376                     break;
1377                 case 'o':
1378                 case 'O':
1379                     *outputDir = *++argv;
1380                     --argc;
1381                     break;
1382                 case 'p':
1383                 case 'P':
1384                      if(strcmp(*++argv,"NT")) platform = unix_symbols;
1385                     --argc;
1386                     break;
1387                 default:
1388                     PrintLongUsage;
1389                     exit(1);
1390                     break;
1391             }
1392         } else {
1393             PrintShortUsage;
1394             exit(1);
1395         }
1396     }
1397     if (!*serverName)
1398         FATAL("Please set server name using -s switch\n");
1399 }
1400
1401
1402 void main(int argc, char **argv)
1403 {
1404     FILE *table_h, *srv_h, *xg_h, *clt_h, *mak_h;
1405     int i, j;
1406     rpcArgs args;
1407     char *name, *ifName;
1408     char *serverName = NULL;
1409     char *ipFileName = NULL;
1410     char *outputDir = NULL;
1411     int sign_no=0, start_no, srv_no;
1412
1413     ProcessCmdLine(argc, argv, &serverName, &ipFileName, &outputDir);
1414
1415     /* open input file */
1416     table_h = fopen(ipFileName, "r");
1417     MEM_CHK(table_h, "main: Unable to open input file\n");
1418
1419     srv_no = 1;
1420     start_no = sign_no;
1421
1422     /*
1423      * open the first set of output files
1424      */
1425
1426     name = GetName(serverName, srv_no);
1427
1428     srv_h = OpenOutFile(outputDir, name, "Srv.c");
1429     xg_h = OpenOutFile(outputDir, name, ".xg");
1430     clt_h = OpenOutFile(outputDir, name, "Clt.c");
1431     mak_h = OpenOutFile(outputDir, name, ".mak");
1432
1433     WriteXGHeader(serverName, xg_h, srv_no);
1434     WriteServHeader(srv_h, serverName, srv_no);
1435     WriteCltHeader(serverName, srv_no, clt_h);
1436     WriteMake(serverName, srv_no, mak_h);
1437
1438     ifName = name;
1439
1440     /* read the table */
1441     while (fscanf(table_h, "%d", &(args.argCount)) != EOF) {
1442
1443         /* increment signature number 8.3 format-- only 10^7 dif sign */
1444         sign_no++;
1445         if (sign_no > 1.0e+7)
1446             FATAL("Max no: of signatures overflow\n");
1447
1448         /* allocate for the arg struct */
1449         args.argDescr = (arg_tuple *)calloc(args.argCount, sizeof(arg_tuple));
1450         MEM_CHK(args.argDescr, "main: Out of memory -- args.argDescr\n");
1451
1452         /* pick out the dirs and the types */
1453         for (i=0; i < args.argCount; i++) {
1454             if(!fscanf(table_h, " ( %s %s )", args.argDescr[i].direction,
1455                        args.argDescr[i].type)) {
1456                 FATAL("main: Incorrect input file format\n");
1457             }
1458         }
1459
1460         /*
1461          * switch files when we hit TESTS_PER_FILE
1462          */
1463         if (sign_no - start_no >= TESTS_PER_FILE) {
1464             /*
1465              * Finish up the current files
1466              */
1467             WriteServTrailer(srv_h);
1468             WriteCltTrailer(serverName, start_no, sign_no, clt_h);
1469             fclose(xg_h);
1470             fclose(srv_h);
1471             fclose(clt_h);
1472             fclose(mak_h);
1473
1474             /*
1475              * Open the next set of output files
1476              */
1477
1478             srv_no++;
1479             free(ifName);
1480             name = GetName(serverName, srv_no);
1481
1482             srv_h = OpenOutFile(outputDir, name, "Srv.c");
1483             xg_h = OpenOutFile(outputDir, name, ".xg");
1484             clt_h = OpenOutFile(outputDir, name, "Clt.c");
1485             mak_h = OpenOutFile(outputDir, name, ".mak");
1486             WriteXGHeader(serverName, xg_h, srv_no);
1487             WriteServHeader(srv_h, serverName, srv_no);
1488             WriteCltHeader(serverName, srv_no, clt_h);
1489             WriteMake(serverName, srv_no, mak_h);
1490
1491             start_no = sign_no;
1492             ifName = name;
1493         }
1494
1495         /* initialize parameter values */
1496         for (i=0; i<args.argCount; i++) {
1497             for (j = 0 ; j < IDL_FIX_ARRAY_SIZE ; j++) {
1498                 args.argDescr[i].inValue[j] = NULL;
1499                 args.argDescr[i].inValue2[j] = NULL;
1500                 args.argDescr[i].outValue[j] = NULL;
1501                 args.argDescr[i].outValue2[j] = NULL;
1502             }
1503         }
1504         GenParamValues(&args);
1505
1506         /* write rpc desc into body of the interface */
1507         WriteXG(&args, xg_h, serverName, sign_no);
1508
1509         /* write the rpc into the manager file */
1510         WriteServC(&args, srv_h, serverName, sign_no);
1511
1512         /* write out ITL test */
1513         WriteClt(&args, serverName, sign_no, clt_h);
1514
1515         /* free saved values */
1516         for (i=0; i<args.argCount; i++) {
1517             for (j = 0 ; j < IDL_FIX_ARRAY_SIZE ; j++) {
1518                 if (args.argDescr[i].inValue[j])
1519                     free(args.argDescr[i].inValue[j]);
1520                 if (args.argDescr[i].inValue2[j])
1521                     free(args.argDescr[i].inValue2[j]);
1522                 if (args.argDescr[i].outValue[j])
1523                     free(args.argDescr[i].outValue[j]);
1524                 if (args.argDescr[i].outValue2[j])
1525                     free(args.argDescr[i].outValue2[j]);
1526             }
1527         }
1528         free(args.argDescr);
1529     }
1530
1531     WriteServTrailer(srv_h);
1532     WriteCltTrailer(serverName, start_no, (sign_no +1), clt_h);
1533
1534     fclose(clt_h);
1535
1536     fclose(table_h);
1537     fclose(xg_h);
1538     fclose(srv_h);
1539     fclose(mak_h);
1540
1541     /*
1542      * create 1 makefile that drives all the rest
1543      */
1544
1545     mak_h = OpenOutFile(outputDir, "Makefile", "");
1546     fprintf(mak_h, "\ntest:all\ntests:all\nall:\n");
1547     fprintf(mak_h, "%s", platform[8]);
1548     for(i=1;i<=srv_no;i++)
1549         fprintf(mak_h, "\t%s %s%d.mak %s\n", 
1550                 platform[0], serverName, i, platform[5]);
1551     fprintf(mak_h, "\nclean:\n");
1552     for(i=1;i<=srv_no;i++)
1553         fprintf(mak_h, "\t%s %s%d.mak clean\n", platform[0], serverName, i);
1554     fclose(mak_h);
1555
1556     exit(0);
1557 }