1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  27 /* All Rights Reserved */
  28 /*
  29  * University Copyright- Copyright (c) 1982, 1986, 1988
  30  * The Regents of the University of California
  31  * All Rights Reserved
  32  *
  33  * University Acknowledgment- Portions of this document are derived from
  34  * software developed by the University of California, Berkeley, and its
  35  * contributors.
  36  */
  37 
  38 /*
  39  * rpc_clntout.c, Client-stub outputter for the RPC protocol compiler
  40  */
  41 #include <stdio.h>
  42 #include <string.h>
  43 #include <rpc/types.h>
  44 #include "rpc_parse.h"
  45 #include "rpc_util.h"
  46 
  47 extern void pdeclaration(char *, declaration *, int, char *);
  48 extern void printarglist(proc_list *, char *, char *, char *);
  49 
  50 static void write_program(definition *);
  51 static void printbody(proc_list *);
  52 
  53 static char RESULT[] = "clnt_res";
  54 
  55 #define DEFAULT_TIMEOUT 25      /* in seconds */
  56 
  57 void
  58 write_stubs(void)
  59 {
  60         list *l;
  61         definition *def;
  62 
  63         f_print(fout,
  64             "\n/* Default timeout can be changed using clnt_control() */\n");
  65         f_print(fout, "static struct timeval TIMEOUT = { %d, 0 };\n",
  66             DEFAULT_TIMEOUT);
  67         for (l = defined; l != NULL; l = l->next) {
  68                 def = (definition *) l->val;
  69                 if (def->def_kind == DEF_PROGRAM) {
  70                         write_program(def);
  71                 }
  72         }
  73 }
  74 
  75 static void
  76 write_program(definition *def)
  77 {
  78         version_list *vp;
  79         proc_list *proc;
  80 
  81         for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
  82                 for (proc = vp->procs; proc != NULL; proc = proc->next) {
  83                         f_print(fout, "\n");
  84                         if (mtflag == 0) {
  85                                 ptype(proc->res_prefix, proc->res_type, 1);
  86                                 f_print(fout, "*\n");
  87                                 pvname(proc->proc_name, vp->vers_num);
  88                                 printarglist(proc, RESULT, "clnt", "CLIENT *");
  89                         } else {
  90                                 f_print(fout, "enum clnt_stat \n");
  91                                 pvname(proc->proc_name, vp->vers_num);
  92                                 printarglist(proc, RESULT,  "clnt", "CLIENT *");
  93 
  94                         }
  95                         f_print(fout, "{\n");
  96                         printbody(proc);
  97 
  98                         f_print(fout, "}\n");
  99                 }
 100         }
 101 }
 102 
 103 /*
 104  * Writes out declarations of procedure's argument list.
 105  * In either ANSI C style, in one of old rpcgen style (pass by reference),
 106  * or new rpcgen style (multiple arguments, pass by value);
 107  */
 108 
 109 /* sample addargname = "clnt"; sample addargtype = "CLIENT * " */
 110 
 111 void
 112 printarglist(proc_list *proc, char *result, char *addargname, char *addargtype)
 113 {
 114         bool_t oneway = streq(proc->res_type, "oneway");
 115         decl_list *l;
 116 
 117         if (!newstyle) {
 118                 /* old style: always pass argument by reference */
 119                 if (Cflag) {    /* C++ style heading */
 120                         f_print(fout, "(");
 121                         ptype(proc->args.decls->decl.prefix,
 122                             proc->args.decls->decl.type, 1);
 123 
 124                         if (mtflag) {   /* Generate result field */
 125                                 f_print(fout, "*argp, ");
 126                                 if (!oneway) {
 127                                         ptype(proc->res_prefix,
 128                                             proc->res_type, 1);
 129                                         f_print(fout, "*%s, ", result);
 130                                 }
 131                                 f_print(fout, "%s%s)\n",
 132                                     addargtype, addargname);
 133                         } else
 134                                 f_print(fout, "*argp, %s%s)\n",
 135                                     addargtype, addargname);
 136                 } else {
 137                         if (!mtflag)
 138                                 f_print(fout, "(argp, %s)\n", addargname);
 139                         else {
 140                                 f_print(fout, "(argp, ");
 141                                 if (!oneway) {
 142                                         f_print(fout, "%s, ",
 143                                             result);
 144                                 }
 145                                 f_print(fout, "%s)\n",
 146                                     addargname);
 147                         }
 148                         f_print(fout, "\t");
 149                         ptype(proc->args.decls->decl.prefix,
 150                             proc->args.decls->decl.type, 1);
 151                         f_print(fout, "*argp;\n");
 152                         if (mtflag && !oneway) {
 153                                 f_print(fout, "\t");
 154                                 ptype(proc->res_prefix, proc->res_type, 1);
 155                                 f_print(fout, "*%s;\n", result);
 156                         }
 157                 }
 158         } else if (streq(proc->args.decls->decl.type, "void")) {
 159                 /* newstyle, 0 argument */
 160                 if (mtflag) {
 161                         f_print(fout, "(");
 162 
 163                         if (Cflag) {
 164                                 if (!oneway) {
 165                                         ptype(proc->res_prefix,
 166                                             proc->res_type, 1);
 167                                         f_print(fout, "*%s, ", result);
 168                                 }
 169                                 f_print(fout, "%s%s)\n",
 170                                     addargtype, addargname);
 171                         } else
 172                                 f_print(fout, "(%s)\n", addargname);
 173 
 174                 } else
 175                 if (Cflag)
 176                         f_print(fout, "(%s%s)\n", addargtype, addargname);
 177                 else
 178                         f_print(fout, "(%s)\n", addargname);
 179         } else {
 180                 /* new style, 1 or multiple arguments */
 181                 if (!Cflag) {
 182                         f_print(fout, "(");
 183                         for (l = proc->args.decls;  l != NULL; l = l->next)
 184                                 f_print(fout, "%s, ", l->decl.name);
 185                         if (mtflag && !oneway)
 186                                 f_print(fout, "%s, ", result);
 187 
 188                         f_print(fout, "%s)\n", addargname);
 189                         for (l = proc->args.decls; l != NULL; l = l->next) {
 190                                 pdeclaration(proc->args.argname,
 191                                     &l->decl, 1, ";\n");
 192                         }
 193                         if (mtflag && !oneway) {
 194                                 f_print(fout, "\t");
 195                                 ptype(proc->res_prefix, proc->res_type, 1);
 196                                 f_print(fout, "*%s;\n", result);
 197                         }
 198 
 199                 } else {        /* C++ style header */
 200                         f_print(fout, "(");
 201                         for (l = proc->args.decls; l != NULL; l = l->next) {
 202                                 pdeclaration(proc->args.argname, &l->decl, 0,
 203                                     ", ");
 204                         }
 205                         if (mtflag && !oneway) {
 206                                 ptype(proc->res_prefix, proc->res_type, 1);
 207                                 f_print(fout, "*%s, ", result);
 208 
 209                         }
 210                         f_print(fout, "%s%s)\n", addargtype, addargname);
 211                 }
 212         }
 213 
 214         if (!Cflag)
 215                 f_print(fout, "\t%s%s;\n", addargtype, addargname);
 216 }
 217 
 218 
 219 
 220 static char *
 221 ampr(char *type)
 222 {
 223         if (isvectordef(type, REL_ALIAS)) {
 224                 return ("");
 225         } else {
 226                 return ("&");
 227         }
 228 }
 229 
 230 static void
 231 printbody(proc_list *proc)
 232 {
 233         decl_list *l;
 234         bool_t args2 = (proc->arg_num > 1);
 235         bool_t oneway = streq(proc->res_type, "oneway");
 236 
 237         /*
 238          * For new style with multiple arguments, need a structure in which
 239          *  to stuff the arguments.
 240          */
 241         if (newstyle && args2) {
 242                 f_print(fout, "\t%s", proc->args.argname);
 243                 f_print(fout, " arg;\n");
 244         }
 245         if (!oneway) {
 246                 if (!mtflag) {
 247                         f_print(fout, "\tstatic ");
 248                         if (streq(proc->res_type, "void")) {
 249                                 f_print(fout, "char ");
 250                         } else {
 251                                 ptype(proc->res_prefix, proc->res_type, 0);
 252                         }
 253                         f_print(fout, "%s;\n", RESULT);
 254                         f_print(fout, "\n");
 255                         f_print(fout,
 256                             "\t(void) memset(%s%s, 0, sizeof (%s));\n",
 257                             ampr(proc->res_type), RESULT, RESULT);
 258 
 259                 }
 260                 if (newstyle && !args2 &&
 261                     (streq(proc->args.decls->decl.type, "void"))) {
 262                         /* newstyle, 0 arguments */
 263 
 264                         if (mtflag)
 265                                 f_print(fout, "\t return ");
 266                         else
 267                                 f_print(fout, "\t if ");
 268 
 269                         f_print(fout,
 270                             "(clnt_call(clnt, %s,\n\t\t(xdrproc_t)xdr_void, ",
 271                             proc->proc_name);
 272                         f_print(fout,
 273                             "NULL,\n\t\t(xdrproc_t)xdr_%s, "
 274                             "(caddr_t)%s%s,",
 275                             stringfix(proc->res_type),
 276                             (mtflag)?"":ampr(proc->res_type),
 277                             RESULT);
 278 
 279                         if (mtflag)
 280                                 f_print(fout, "\n\t\tTIMEOUT));\n");
 281                         else
 282                                 f_print(fout,
 283                                     "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n");
 284 
 285                 } else if (newstyle && args2) {
 286                         /*
 287                          * Newstyle, multiple arguments
 288                          * stuff arguments into structure
 289                          */
 290                         for (l = proc->args.decls;  l != NULL; l = l->next) {
 291                                 f_print(fout, "\targ.%s = %s;\n",
 292                                     l->decl.name, l->decl.name);
 293                         }
 294                         if (mtflag)
 295                                 f_print(fout, "\treturn ");
 296                         else
 297                                 f_print(fout, "\tif ");
 298                         f_print(fout,
 299                             "(clnt_call(clnt, %s,\n\t\t(xdrproc_t)xdr_%s",
 300                             proc->proc_name, proc->args.argname);
 301                         f_print(fout,
 302                             ", (caddr_t)&arg,\n\t\t(xdrproc_t)xdr_%s, "
 303                             "(caddr_t)%s%s,",
 304                             stringfix(proc->res_type),
 305                             (mtflag)?"":ampr(proc->res_type),
 306                             RESULT);
 307                         if (mtflag)
 308                                 f_print(fout, "\n\t\tTIMEOUT));\n");
 309                         else
 310                                 f_print(fout,
 311                                     "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n");
 312                 } else {                /* single argument, new or old style */
 313                         if (!mtflag)
 314                                 f_print(fout,
 315                                     "\tif (clnt_call(clnt, "
 316                                     "%s,\n\t\t(xdrproc_t)xdr_%s, "
 317                                     "(caddr_t)%s%s,\n\t\t(xdrproc_t)xdr_%s, "
 318                                     "(caddr_t)%s%s,\n\t\tTIMEOUT) != "
 319                                     "RPC_SUCCESS) {\n",
 320                                     proc->proc_name,
 321                                     stringfix(proc->args.decls->decl.type),
 322                                     (newstyle ? "&" : ""),
 323                                     (newstyle ?
 324                                     proc->args.decls->decl.name :
 325                                     "argp"),
 326                                     stringfix(proc->res_type),
 327                                     ampr(proc->res_type),
 328                                     RESULT);
 329                         else
 330                                 f_print(fout,
 331                                     "\treturn (clnt_call(clnt, "
 332                                     "%s,\n\t\t(xdrproc_t)xdr_%s, "
 333                                     "(caddr_t)%s%s,\n\t\t(xdrproc_t)xdr_%s, "
 334                                     "(caddr_t)%s%s,\n\t\tTIMEOUT));\n",
 335                                     proc->proc_name,
 336                                     stringfix(proc->args.decls->decl.type),
 337                                     (newstyle ? "&" : ""),
 338                                     (newstyle ?
 339                                     proc->args.decls->decl.name :
 340                                     "argp"),
 341                                     stringfix(proc->res_type), "",
 342                                     RESULT);
 343                 }
 344                 if (!mtflag) {
 345                         f_print(fout, "\t\treturn (NULL);\n");
 346                         f_print(fout, "\t}\n");
 347 
 348                         if (streq(proc->res_type, "void")) {
 349                                 f_print(fout, "\treturn ((void *)%s%s);\n",
 350                                     ampr(proc->res_type), RESULT);
 351                         } else {
 352                                 f_print(fout, "\treturn (%s%s);\n",
 353                                     ampr(proc->res_type), RESULT);
 354                         }
 355                 }
 356         } else {
 357                 /* oneway call */
 358                 if (!mtflag) {
 359                         f_print(fout, "\tstatic enum clnt_stat ");
 360                         f_print(fout, "%s;\n", RESULT);
 361                         f_print(fout, "\n");
 362                         f_print(fout,
 363                             "\t(void) memset(&%s, 0, sizeof (%s));\n",
 364                             RESULT, RESULT);
 365 
 366                 }
 367                 if (newstyle && !args2 &&
 368                     (streq(proc->args.decls->decl.type, "void"))) {
 369                         /* newstyle, 0 arguments */
 370 
 371                         if (mtflag)
 372                                 f_print(fout, "\t return (");
 373                         else
 374                                 f_print(fout, "\t if ((%s = ", RESULT);
 375 
 376                         f_print(fout,
 377                             "clnt_send(clnt, %s,\n\t\t(xdrproc_t)xdr_void, ",
 378                             proc->proc_name);
 379                         f_print(fout, "NULL)");
 380 
 381                         if (mtflag)
 382                                 f_print(fout, ");\n");
 383                         else
 384                                 f_print(fout, ") != RPC_SUCCESS) {\n");
 385 
 386                 } else if (newstyle && args2) {
 387                         /*
 388                          * Newstyle, multiple arguments
 389                          * stuff arguments into structure
 390                          */
 391                         for (l = proc->args.decls;  l != NULL; l = l->next) {
 392                                 f_print(fout, "\targ.%s = %s;\n",
 393                                     l->decl.name, l->decl.name);
 394                         }
 395                         if (mtflag)
 396                                 f_print(fout, "\treturn (");
 397                         else
 398                                 f_print(fout, "\tif ((%s =", RESULT);
 399                         f_print(fout,
 400                             "clnt_send(clnt, %s,\n\t\t(xdrproc_t)xdr_%s",
 401                             proc->proc_name, proc->args.argname);
 402                         f_print(fout,
 403                             ", (caddr_t)&arg)");
 404                         if (mtflag)
 405                                 f_print(fout, ");\n");
 406                         else
 407                                 f_print(fout, ") != RPC_SUCCESS) {\n");
 408                 } else {                /* single argument, new or old style */
 409                         if (!mtflag)
 410                                 f_print(fout,
 411                                     "\tif ((%s = clnt_send(clnt, "
 412                                     "%s,\n\t\t(xdrproc_t)xdr_%s, "
 413                                     "(caddr_t)%s%s)) != RPC_SUCCESS) {\n",
 414                                     RESULT,
 415                                     proc->proc_name,
 416                                     stringfix(proc->args.decls->decl.type),
 417                                     (newstyle ? "&" : ""),
 418                                     (newstyle ?
 419                                     proc->args.decls->decl.name :
 420                                     "argp"));
 421                         else
 422 
 423                                 f_print(fout,
 424                                     "\treturn (clnt_send(clnt, "
 425                                     "%s,\n\t\t(xdrproc_t)xdr_%s, "
 426                                     "(caddr_t)%s%s));\n",
 427                                     proc->proc_name,
 428                                     stringfix(proc->args.decls->decl.type),
 429                                     (newstyle ? "&" : ""),
 430                                     (newstyle ?
 431                                     proc->args.decls->decl.name :
 432                                     "argp"));
 433                 }
 434                 if (!mtflag) {
 435                         f_print(fout, "\t\treturn (NULL);\n");
 436                         f_print(fout, "\t}\n");
 437 
 438                         f_print(fout, "\treturn ((void *)&%s);\n",
 439                             RESULT);
 440                 }
 441         }
 442 }