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