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