remote_generator.pl 44.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#!/usr/bin/perl -w
#
# This script parses remote_protocol.x or qemu_protocol.x and produces lots of
# boilerplate code for both ends of the remote connection.
#
# The first non-option argument specifies the prefix to be searched for, and
# output to, the boilerplate code.  The second non-option argument is the
# file you want to operate on.  For instance, to generate the dispatch table
# for both remote_protocol.x and qemu_protocol.x, you would run the
# following:
#
# remote_generator.pl -c -t remote ../src/remote/remote_protocol.x
# remote_generator.pl -t qemu ../src/remote/qemu_protocol.x
#
# By Richard Jones <rjones@redhat.com>
16
# Extended by Matthias Bolte <matthias.bolte@googlemail.com>
17 18 19 20 21 22

use strict;

use Getopt::Std;

# Command line options.
23 24
our ($opt_p, $opt_t, $opt_a, $opt_r, $opt_d, $opt_c, $opt_b, $opt_k);
getopts ('ptardcbk');
25

26 27 28 29
my $structprefix = shift or die "missing prefix argument";
my $protocol = shift or die "missing protocol argument";
my @autogen;

30 31 32 33 34 35 36
my $procprefix = uc $structprefix;

# Convert name_of_call to NameOfCall.
sub name_to_ProcName {
    my $name = shift;
    my @elems = split /_/, $name;
    @elems = map ucfirst, @elems;
37
    @elems = map { $_ =~ s/Nwfilter/NWFilter/; $_ =~ s/Xml/XML/;
38
                   $_ =~ s/Uri/URI/; $_ =~ s/Uuid/UUID/; $_ =~ s/Id/ID/;
39
                   $_ =~ s/Mac/MAC/; $_ =~ s/Cpu/CPU/; $_ =~ s/Os/OS/;
40
                   $_ =~ s/Nmi/NMI/; $_ } @elems;
41 42 43 44 45
    join "", @elems
}

# Read the input file (usually remote_protocol.x) and form an
# opinion about the name, args and return type of each RPC.
46
my ($name, $ProcName, $id, $flags, $gen, %calls, @calls);
47 48 49 50 51 52 53 54 55 56 57 58 59

# only generate a close method if -c was passed
if ($opt_c) {
    # REMOTE_PROC_CLOSE has no args or ret.
    $calls{close} = {
        name => "close",
        ProcName => "Close",
        UC_NAME => "CLOSE",
        args => "void",
        ret => "void",
    };
}

60
my $collect_args_members = 0;
61
my $collect_ret_members = 0;
62 63
my $last_name;

64 65 66
open PROTOCOL, "<$protocol" or die "cannot open $protocol: $!";

while (<PROTOCOL>) {
67 68 69 70 71 72
    if ($collect_args_members) {
        if (/^};/) {
            $collect_args_members = 0;
        } elsif ($_ =~ m/^\s*(.*\S)\s*$/) {
            push(@{$calls{$name}->{args_members}}, $1);
        }
73 74 75 76 77 78
    } elsif ($collect_ret_members) {
        if (/^};/) {
            $collect_ret_members = 0;
        } elsif ($_ =~ m/^\s*(.*\S)\s*$/) {
            push(@{$calls{$name}->{ret_members}}, $1);
        }
79
    } elsif (/^struct ${structprefix}_(.*)_args/) {
80 81 82 83 84 85 86 87 88 89 90
        $name = $1;
        $ProcName = name_to_ProcName ($name);

        die "duplicate definition of ${structprefix}_${name}_args"
            if exists $calls{$name};

        $calls{$name} = {
            name => $name,
            ProcName => $ProcName,
            UC_NAME => uc $name,
            args => "${structprefix}_${name}_args",
91 92
            args_members => [],
            ret => "void"
93 94
        };

95
        $collect_args_members = 1;
96
        $collect_ret_members = 0;
97
        $last_name = $name;
98 99 100 101 102 103 104 105 106 107 108 109
    } elsif (/^struct ${structprefix}_(.*)_ret/) {
        $name = $1;
        $ProcName = name_to_ProcName ($name);

        if (exists $calls{$name}) {
            $calls{$name}->{ret} = "${structprefix}_${name}_ret";
        } else {
            $calls{$name} = {
                name => $name,
                ProcName => $ProcName,
                UC_NAME => uc $name,
                args => "void",
110 111
                ret => "${structprefix}_${name}_ret",
                ret_members => []
112 113
            }
        }
114 115

        $collect_args_members = 0;
116 117
        $collect_ret_members = 1;
        $last_name = $name;
118 119 120 121 122 123 124 125 126
    } elsif (/^struct ${structprefix}_(.*)_msg/) {
        $name = $1;
        $ProcName = name_to_ProcName ($name);

        $calls{$name} = {
            name => $name,
            ProcName => $ProcName,
            UC_NAME => uc $name,
            msg => "${structprefix}_${name}_msg"
127 128 129
        };

        $collect_args_members = 0;
130
        $collect_ret_members = 0;
131
    } elsif (/^\s*${procprefix}_PROC_(.*?)\s*=\s*(\d+)\s*,?(.*)$/) {
132 133
        $name = lc $1;
        $id = $2;
134
        $flags = $3;
135 136
        $ProcName = name_to_ProcName ($name);

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
        if ($opt_b or $opt_k) {
            if (!($flags =~ m/^\s*\/\*\s*(\S+)\s+(\S+)\s*\*\/\s*$/)) {
                die "invalid generator flags for ${procprefix}_PROC_${name}"
            }

            $gen = $opt_b ? $1 : $2;

            if ($gen eq "autogen") {
                push(@autogen, $ProcName);
            } elsif ($gen eq "skipgen") {
                # ignore it
            } else {
                die "invalid generator flags for ${procprefix}_PROC_${name}"
            }
        }

153
        $calls[$id] = $calls{$name};
154 155

        $collect_args_members = 0;
156
        $collect_ret_members = 0;
157 158
    } else {
        $collect_args_members = 0;
159
        $collect_ret_members = 0;
160 161 162
    }
}

163 164
close(PROTOCOL);

165 166 167 168 169 170 171 172 173
#----------------------------------------------------------------------
# Output

print <<__EOF__;
/* Automatically generated by remote_generator.pl.
 * Do not edit this file.  Any changes you make will be lost.
 */
__EOF__

174 175 176 177
if (!$opt_b and !$opt_k) {
    print "\n";
}

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
# Debugging.
if ($opt_d) {
    my @keys = sort (keys %calls);
    foreach (@keys) {
        print "$_:\n";
        print "        name $calls{$_}->{name} ($calls{$_}->{ProcName})\n";
        print "        $calls{$_}->{args} -> $calls{$_}->{ret}\n";
    }
}

# Prototypes for dispatch functions ("remote_dispatch_prototypes.h").
elsif ($opt_p) {
    my @keys = sort (keys %calls);
    foreach (@keys) {
        # Skip things which are REMOTE_MESSAGE
        next if $calls{$_}->{msg};

        print "static int ${structprefix}Dispatch$calls{$_}->{ProcName}(\n";
        print "    struct qemud_server *server,\n";
        print "    struct qemud_client *client,\n";
        print "    virConnectPtr conn,\n";
        print "    remote_message_header *hdr,\n";
        print "    remote_error *rerr,\n";
        print "    $calls{$_}->{args} *args,\n";
        print "    $calls{$_}->{ret} *ret);\n";
    }
}

# Union of all arg types
# ("remote_dispatch_args.h").
elsif ($opt_a) {
    for ($id = 0 ; $id <= $#calls ; $id++) {
        if (defined $calls[$id] &&
            !$calls[$id]->{msg} &&
            $calls[$id]->{args} ne "void") {
            print "    $calls[$id]->{args} val_$calls[$id]->{args};\n";
        }
    }
}

# Union of all arg types
# ("remote_dispatch_ret.h").
elsif ($opt_r) {
    for ($id = 0 ; $id <= $#calls ; $id++) {
        if (defined $calls[$id] &&
            !$calls[$id]->{msg} &&
            $calls[$id]->{ret} ne "void") {
            print "    $calls[$id]->{ret} val_$calls[$id]->{ret};\n";
        }
    }
}

# Inside the switch statement, prepare the 'fn', 'args_filter', etc
# ("remote_dispatch_table.h").
elsif ($opt_t) {
    for ($id = 0 ; $id <= $#calls ; $id++) {
        if (defined $calls[$id] && !$calls[$id]->{msg}) {
            print "{   /* $calls[$id]->{ProcName} => $id */\n";
            print "    .fn = (dispatch_fn) ${structprefix}Dispatch$calls[$id]->{ProcName},\n";
            if ($calls[$id]->{args} ne "void") {
                print "    .args_filter = (xdrproc_t) xdr_$calls[$id]->{args},\n";
            } else {
                print "    .args_filter = (xdrproc_t) xdr_void,\n";
            }
            if ($calls[$id]->{ret} ne "void") {
                print "    .ret_filter = (xdrproc_t) xdr_$calls[$id]->{ret},\n";
            } else {
                print "    .ret_filter = (xdrproc_t) xdr_void,\n";
            }
            print "},\n";
        } else {
            if ($calls[$id]->{msg}) {
                print "{   /* Async event $calls[$id]->{ProcName} => $id */\n";
            } else {
                print "{   /* (unused) => $id */\n";
            }
            print "    .fn = NULL,\n";
            print "    .args_filter = (xdrproc_t) xdr_void,\n";
            print "    .ret_filter = (xdrproc_t) xdr_void,\n";
            print "},\n";
        }
    }
}
261

262
# Bodies for dispatch functions ("remote_dispatch_bodies.h").
263
elsif ($opt_b) {
264
    my %generate = map { $_ => 1 } @autogen;
265 266 267 268 269 270
    my @keys = sort (keys %calls);

    foreach (@keys) {
        # skip things which are REMOTE_MESSAGE
        next if $calls{$_}->{msg};

271 272
        # skip procedures not on generate list
        next if ! exists($generate{$calls{$_}->{ProcName}});
273 274 275

        my $has_node_device = 0;
        my @vars_list = ();
276
        my @optionals_list = ();
277 278
        my @getters_list = ();
        my @args_list = ();
279
        my @ret_list = ();
280
        my @free_list = ();
281
        my @free_list_on_error = ("remoteDispatchError(rerr);");
282

283
        # handle arguments to the function
284 285
        if ($calls{$_}->{args} ne "void") {
            # node device is special, as it's identified by name
286 287 288
            if ($calls{$_}->{args} =~ m/^remote_node_device_/ and
                !($calls{$_}->{args} =~ m/^remote_node_device_lookup_by_name_/) and
                !($calls{$_}->{args} =~ m/^remote_node_device_create_xml_/)) {
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
                $has_node_device = 1;
                push(@vars_list, "virNodeDevicePtr dev = NULL");
                push(@getters_list,
                     "    if (!(dev = virNodeDeviceLookupByName(conn, args->name)))\n" .
                     "        goto cleanup;\n");
                push(@args_list, "dev");
                push(@free_list,
                     "    if (dev)\n" .
                     "        virNodeDeviceFree(dev);");
            }

            foreach my $args_member (@{$calls{$_}->{args_members}}) {
                if ($args_member =~ m/^remote_nonnull_string name;/ and $has_node_device) {
                    # ignore the name arg for node devices
                    next
304 305 306 307
                } elsif ($args_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|secret|nwfilter) (\S+);/) {
                    my $type_name = name_to_ProcName($1);

                    push(@vars_list, "vir${type_name}Ptr $2 = NULL");
308
                    push(@getters_list,
309
                         "    if (!($2 = get_nonnull_$1(conn, args->$2)))\n" .
310
                         "        goto cleanup;\n");
311
                    push(@args_list, "$2");
312
                    push(@free_list,
313 314
                         "    if ($2)\n" .
                         "        vir${type_name}Free($2);");
315 316 317 318
                } elsif ($args_member =~ m/^remote_nonnull_domain_snapshot /) {
                    push(@vars_list, "virDomainPtr dom = NULL");
                    push(@vars_list, "virDomainSnapshotPtr snapshot = NULL");
                    push(@getters_list,
319
                         "    if (!(dom = get_nonnull_domain(conn, args->snap.dom)))\n" .
320 321 322 323 324 325 326 327 328 329
                         "        goto cleanup;\n" .
                         "\n" .
                         "    if (!(snapshot = get_nonnull_domain_snapshot(dom, args->snap)))\n" .
                         "        goto cleanup;\n");
                    push(@args_list, "snapshot");
                    push(@free_list,
                         "    if (snapshot)\n" .
                         "        virDomainSnapshotFree(snapshot);\n" .
                         "    if (dom)\n" .
                         "        virDomainFree(dom);");
330
                } elsif ($args_member =~ m/^(remote_string|remote_nonnull_string|remote_uuid|opaque) (\S+)<\S+>;/) {
331 332 333 334 335
                    if (! @args_list) {
                        push(@args_list, "conn");
                    }

                    if ($calls{$_}->{ProcName} eq "SecretSetValue") {
336
                        push(@args_list, "(const unsigned char *)args->$2.$2_val");
337
                    } elsif ($calls{$_}->{ProcName} eq "CPUBaseline") {
338
                        push(@args_list, "(const char **)args->$2.$2_val");
339
                    } else {
340
                        push(@args_list, "args->$2.$2_val");
341 342
                    }

343 344 345 346 347
                    push(@args_list, "args->$2.$2_len");
                } elsif ($args_member =~ m/<\S+>;/ or $args_member =~ m/\[\S+\];/) {
                    # just make all other array types fail
                    die "unhandled type for argument value: $args_member";
                } elsif ($args_member =~ m/^remote_uuid (\S+);/) {
348 349 350 351
                    if (! @args_list) {
                        push(@args_list, "conn");
                    }

352 353 354 355
                    push(@args_list, "(unsigned char *) args->$1");
                } elsif ($args_member =~ m/^remote_string (\S+);/) {
                    if (! @args_list) {
                        push(@args_list, "conn");
356
                    }
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372

                    push(@vars_list, "char *$1");
                    push(@optionals_list, "$1");
                    push(@args_list, "$1");
                } elsif ($args_member =~ m/^remote_nonnull_string (\S+);/) {
                    if (! @args_list) {
                        push(@args_list, "conn");
                    }

                    push(@args_list, "args->$1");
                } elsif ($args_member =~ m/^(unsigned )?(int|hyper) (\S+);/) {
                    if (! @args_list) {
                        push(@args_list, "conn");
                    }

                    push(@args_list, "args->$3");
373
                } elsif ($args_member =~ m/^(\/)?\*/) {
374 375 376
                    # ignore comments
                } else {
                    die "unhandled type for argument value: $args_member";
377 378 379 380
                }
            }
        }

381
        # handle return values of the function
382 383 384
        my $single_ret_var = "undefined";
        my $single_ret_by_ref = 0;
        my $single_ret_check = " == undefined";
385 386 387 388
        my $single_ret_as_list = 0;
        my $single_ret_list_name = "undefined";
        my $single_ret_list_max_var = "undefined";
        my $single_ret_list_max_define = "undefined";
389 390 391 392 393 394
        my $multi_ret = 0;

        if ($calls{$_}->{ret} ne "void" and
            scalar(@{$calls{$_}->{ret_members}}) > 1) {
            $multi_ret = 1;
        }
395 396 397

        if ($calls{$_}->{ret} ne "void") {
            foreach my $ret_member (@{$calls{$_}->{ret_members}}) {
398
                if ($multi_ret) {
399 400 401 402
                    if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) {
                        push(@ret_list, "memcpy(ret->$3, tmp.$3, sizeof ret->$3);");
                    } elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+);/) {
                        push(@ret_list, "ret->$3 = tmp.$3;");
403 404 405
                    } else {
                        die "unhandled type for multi-return-value: $ret_member";
                    }
406
                } elsif ($ret_member =~ m/^remote_nonnull_string (\S+)<(\S+)>;/) {
407 408
                    push(@vars_list, "int len");
                    push(@ret_list, "ret->$1.$1_len = len;");
409
                    push(@free_list_on_error, "VIR_FREE(ret->$1.$1_val);");
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
                    $single_ret_var = "len";
                    $single_ret_by_ref = 0;
                    $single_ret_check = " < 0";
                    $single_ret_as_list = 1;
                    $single_ret_list_name = $1;
                    $single_ret_list_max_var = "max$1";
                    $single_ret_list_max_define = $2;

                    if ($calls{$_}->{ProcName} eq "NodeListDevices") {
                        my $conn = shift(@args_list);
                        my $cap = shift(@args_list);
                        unshift(@args_list, "ret->$1.$1_val");
                        unshift(@args_list, $cap);
                        unshift(@args_list, $conn);
                    } else {
                        my $conn = shift(@args_list);
                        unshift(@args_list, "ret->$1.$1_val");
                        unshift(@args_list, $conn);
                    }
429
                } elsif ($ret_member =~ m/^remote_nonnull_string (\S+);/) {
430 431 432 433 434
                    push(@vars_list, "char *$1");
                    push(@ret_list, "ret->$1 = $1;");
                    $single_ret_var = $1;
                    $single_ret_by_ref = 0;
                    $single_ret_check = " == NULL";
435
                } elsif ($ret_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|node_device|secret|nwfilter|domain_snapshot) (\S+);/) {
436 437 438 439
                    my $type_name = name_to_ProcName($1);

                    push(@vars_list, "vir${type_name}Ptr $2 = NULL");
                    push(@ret_list, "make_nonnull_$1(&ret->$2, $2);");
440
                    push(@free_list,
441 442 443
                         "    if ($2)\n" .
                         "        vir${type_name}Free($2);");
                    $single_ret_var = $2;
444 445
                    $single_ret_by_ref = 0;
                    $single_ret_check = " == NULL";
446
                } elsif ($ret_member =~ m/^int (\S+)<(\S+)>;/) {
447 448
                    push(@vars_list, "int len");
                    push(@ret_list, "ret->$1.$1_len = len;");
449
                    push(@free_list_on_error, "VIR_FREE(ret->$1.$1_val);");
450 451 452 453 454 455 456 457 458 459 460
                    $single_ret_var = "len";
                    $single_ret_by_ref = 0;
                    $single_ret_check = " < 0";
                    $single_ret_as_list = 1;
                    $single_ret_list_name = $1;
                    $single_ret_list_max_var = "max$1";
                    $single_ret_list_max_define = $2;

                    my $conn = shift(@args_list);
                    unshift(@args_list, "ret->$1.$1_val");
                    unshift(@args_list, $conn);
461
                } elsif ($ret_member =~ m/^int (\S+);/) {
462 463 464 465
                    push(@vars_list, "int $1");
                    push(@ret_list, "ret->$1 = $1;");
                    $single_ret_var = $1;

466
                    if ($calls{$_}->{ProcName} =~ m/GetAutostart$/) {
467 468 469
                        $single_ret_by_ref = 1;
                    } else {
                        $single_ret_by_ref = 0;
470 471 472 473 474 475

                        if ($calls{$_}->{ProcName} eq "CPUCompare") {
                            $single_ret_check = " == VIR_CPU_COMPARE_ERROR";
                        } else {
                            $single_ret_check = " < 0";
                        }
476
                    }
477
                } elsif ($ret_member =~ m/^hyper (\S+)<(\S+)>;/) {
478 479
                    push(@vars_list, "int len");
                    push(@ret_list, "ret->$1.$1_len = len;");
480
                    push(@free_list_on_error, "VIR_FREE(ret->$1.$1_val);");
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
                    $single_ret_var = "len";
                    $single_ret_by_ref = 0;
                    $single_ret_as_list = 1;
                    $single_ret_list_name = $1;
                    $single_ret_list_max_define = $2;

                    my $conn = shift(@args_list);

                    if ($calls{$_}->{ProcName} eq "NodeGetCellsFreeMemory") {
                        $single_ret_check = " <= 0";
                        $single_ret_list_max_var = "maxCells";
                        unshift(@args_list, "(unsigned long long *)ret->$1.$1_val");
                    } else {
                        $single_ret_check = " < 0";
                        $single_ret_list_max_var = "max$1";
                        unshift(@args_list, "ret->$1.$1_val");
                    }

                    unshift(@args_list, $conn);
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
                } elsif ($ret_member =~ m/^(unsigned )?hyper (\S+);/) {
                    my $type_name;
                    my $ret_name = $2;

                    $type_name = $1 if ($1);
                    $type_name .= "long";

                    if ($type_name eq "long" and
                        $calls{$_}->{ProcName} =~ m/^Get(Lib)?Version$/) {
                        # SPECIAL: virConnectGet(Lib)?Version uses unsigned long
                        #          in public API but hyper in XDR protocol
                        $type_name = "unsigned long";
                    }

                    push(@vars_list, "$type_name $ret_name");
                    push(@ret_list, "ret->$ret_name = $ret_name;");
                    $single_ret_var = $ret_name;
517

518 519
                    if ($calls{$_}->{ProcName} eq "DomainGetMaxMemory" or
                        $calls{$_}->{ProcName} eq "NodeGetFreeMemory") {
520 521 522
                        # SPECIAL: virDomainGetMaxMemory and virNodeGetFreeMemory
                        #          return the actual value directly and 0 indicates
                        #          an error
523 524 525 526 527
                        $single_ret_by_ref = 0;
                        $single_ret_check = " == 0";
                    } else {
                        $single_ret_by_ref = 1;
                    }
528 529
                } elsif ($ret_member =~ m/^(\/)?\*/) {
                    # ignore comments
530 531
                } else {
                    die "unhandled type for return value: $ret_member";
532 533 534 535
                }
            }
        }

536
        # select struct type for multi-return-value functions
537 538 539 540 541 542 543 544 545
        if ($multi_ret) {
            if (! @args_list) {
                push(@args_list, "conn");
            }

            my $struct_name = $calls{$_}->{ProcName};
            $struct_name =~ s/Get//;

            if ($calls{$_}->{ProcName} eq "DomainGetBlockInfo") {
546 547
                # SPECIAL: virDomainGetBlockInfo has flags parameter after
                #          the struct parameter in its signature
548 549 550
                my $flags = pop(@args_list);
                push(@args_list, "&tmp");
                push(@args_list, $flags);
551 552 553 554 555
            } elsif ($calls{$_}->{ProcName} eq "DomainBlockStats" ||
                     $calls{$_}->{ProcName} eq "DomainInterfaceStats") {
                # SPECIAL: virDomainBlockStats and virDomainInterfaceStats
                #          have a 'Struct' suffix on the actual struct name
                #          and take the struct size as additional argument
556 557 558 559 560 561 562 563 564 565
                $struct_name .= "Struct";
                push(@args_list, "&tmp");
                push(@args_list, "sizeof tmp");
            } else {
                push(@args_list, "&tmp");
            }

            push(@vars_list, "vir$struct_name tmp");
        }

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
        # print functions signature
        print "\n";
        print "static int\n";
        print "${structprefix}Dispatch$calls{$_}->{ProcName}(\n";
        print "    struct qemud_server *server ATTRIBUTE_UNUSED,\n";
        print "    struct qemud_client *client ATTRIBUTE_UNUSED,\n";
        print "    virConnectPtr conn,\n";
        print "    remote_message_header *hdr ATTRIBUTE_UNUSED,\n";
        print "    remote_error *rerr,\n";
        print "    $calls{$_}->{args} *args";

        if ($calls{$_}->{args} eq "void") {
            print " ATTRIBUTE_UNUSED"
        }

        print ",\n";
        print "    $calls{$_}->{ret} *ret";

        if ($calls{$_}->{ret} eq "void") {
            print " ATTRIBUTE_UNUSED"
        }

        print ")\n";

        # print function body
        print "{\n";
        print "    int rv = -1;\n";

594 595 596 597 598 599 600 601 602 603 604
        foreach my $var (@vars_list) {
            print "    $var;\n";
        }

        print "\n";
        print "    if (!conn) {\n";
        print "        virNetError(VIR_ERR_INTERNAL_ERROR, \"%s\", _(\"connection not open\"));\n";
        print "        goto cleanup;\n";
        print "    }\n";
        print "\n";

605 606 607 608 609 610 611 612 613
        if ($single_ret_as_list) {
            print "    if (args->$single_ret_list_max_var > $single_ret_list_max_define) {\n";
            print "        virNetError(VIR_ERR_INTERNAL_ERROR,\n";
            print "                    \"%s\", _(\"max$single_ret_list_name > $single_ret_list_max_define\"));\n";
            print "        goto cleanup;\n";
            print "    }\n";
            print "\n";
        }

614 615
        print join("\n", @getters_list);

616 617 618
        if (@getters_list) {
            print "\n";
        }
619

620 621 622 623 624 625 626 627
        foreach my $optional (@optionals_list) {
            print "    $optional = args->$optional ? *args->$optional : NULL;\n";
        }

        if (@optionals_list) {
            print "\n";
        }

628 629 630 631 632 633
        if ($calls{$_}->{ret} eq "void") {
            print "    if (vir$calls{$_}->{ProcName}(";
            print join(', ', @args_list);
            print ") < 0)\n";
            print "        goto cleanup;\n";
            print "\n";
634
        } elsif (!$multi_ret) {
635 636 637 638 639
            my $prefix = "";
            my $proc_name = $calls{$_}->{ProcName};

            if (! @args_list) {
                push(@args_list, "conn");
640 641 642 643

                if ($calls{$_}->{ProcName} ne "NodeGetFreeMemory") {
                    $prefix = "Connect"
                }
644 645 646
            }

            if ($calls{$_}->{ProcName} eq "GetSysinfo" or
647
                $calls{$_}->{ProcName} eq "GetMaxVcpus" or
648
                $calls{$_}->{ProcName} eq "DomainXMLFromNative" or
649
                $calls{$_}->{ProcName} eq "DomainXMLToNative" or
650 651
                $calls{$_}->{ProcName} eq "FindStoragePoolSources" or
                $calls{$_}->{ProcName} =~ m/^List/) {
652 653 654
                $prefix = "Connect"
            } elsif ($calls{$_}->{ProcName} eq "SupportsFeature") {
                $prefix = "Drv"
655 656 657 658
            } elsif ($calls{$_}->{ProcName} eq "CPUBaseline") {
                $proc_name = "ConnectBaselineCPU"
            } elsif ($calls{$_}->{ProcName} eq "CPUCompare") {
                $proc_name = "ConnectCompareCPU"
659 660
            }

661 662 663 664 665 666 667 668 669 670
            if ($single_ret_as_list) {
                print "    /* Allocate return buffer. */\n";
                print "    if (VIR_ALLOC_N(ret->$single_ret_list_name.${single_ret_list_name}_val," .
                      " args->$single_ret_list_max_var) < 0) {\n";
                print "        virReportOOMError();\n";
                print "        goto cleanup;\n";
                print "    }\n";
                print "\n";
            }

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
            if ($single_ret_by_ref) {
                print "    if (vir$prefix$proc_name(";
                print join(', ', @args_list);
                print ", &$single_ret_var) < 0)\n";
            } else {
                print "    if (($single_ret_var = vir$prefix$proc_name(";
                print join(', ', @args_list);
                print "))$single_ret_check)\n";
            }

            print "        goto cleanup;\n";
            print "\n";

            if (@ret_list) {
                print "    ";
            }

688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
            print join("\n    ", @ret_list);
            print "\n";
        } else {
            print "    if (vir$calls{$_}->{ProcName}(";
            print join(', ', @args_list);
            print ") < 0)\n";

            print "        goto cleanup;\n";
            print "\n";

            if (@ret_list) {
                print "    ";
            }

            print join("\n    ", @ret_list);
703
            print "\n";
704 705 706 707 708
        }

        print "    rv = 0;\n";
        print "\n";
        print "cleanup:\n";
709 710 711 712 713 714 715 716 717 718 719 720 721
        print "    if (rv < 0)";

        if (scalar(@free_list_on_error) > 1) {
            print " {";
        }

        print "\n        ";
        print join("\n        ", @free_list_on_error);
        print "\n";

        if (scalar(@free_list_on_error) > 1) {
            print "    }\n";
        }
722 723 724

        print join("\n", @free_list);

725 726 727 728
        if (@free_list) {
            print "\n";
        }

729 730 731 732
        print "    return rv;\n";
        print "}\n";
    }
}
733

734
# Bodies for client functions ("remote_client_bodies.h").
735
elsif ($opt_k) {
736
    my %generate = map { $_ => 1 } @autogen;
737 738 739 740 741 742 743 744
    my @keys = sort (keys %calls);

    foreach (@keys) {
        my $call = $calls{$_};

        # skip things which are REMOTE_MESSAGE
        next if $call->{msg};

745 746
        # skip procedures not on generate list
        next if ! exists($generate{$call->{ProcName}});
747

748
        # handle arguments to the function
749 750
        my @args_list = ();
        my @vars_list = ();
751
        my @args_check_list = ();
752 753 754
        my @setters_list = ();
        my $priv_src = "conn";
        my $priv_name = "privateData";
755
        my $call_args = "&args";
756 757

        if ($call->{args} eq "void") {
758
            $call_args = "NULL";
759 760 761 762 763 764 765
        } else {
            push(@vars_list, "$call->{args} args");

            my $is_first_arg = 1;
            my $has_node_device = 0;

            # node device is special
766 767 768
            if ($call->{args} =~ m/^remote_node_/ and
                !($call->{args} =~ m/^remote_node_device_lookup_by_name_/) and
                !($call->{args} =~ m/^remote_node_device_create_xml_/)) {
769
                $has_node_device = 1;
770
                $priv_name = "devMonPrivateData";
771 772 773 774 775 776 777 778 779
            }

            foreach my $args_member (@{$call->{args_members}}) {
                if ($args_member =~ m/^remote_nonnull_string name;/ and $has_node_device) {
                    $priv_src = "dev->conn";
                    push(@args_list, "virNodeDevicePtr dev");
                    push(@setters_list, "args.name = dev->name;");
                } elsif ($args_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|interface|secret|nwfilter|domain_snapshot) (\S+);/) {
                    my $name = $1;
780
                    my $arg_name = $2;
781 782 783 784
                    my $type_name = name_to_ProcName($name);

                    if ($is_first_arg) {
                        if ($name eq "domain_snapshot") {
785
                            $priv_src = "$arg_name->domain->conn";
786
                        } else {
787
                            $priv_src = "$arg_name->conn";
788 789 790 791 792 793 794 795 796
                        }

                        if ($name =~ m/^storage_/) {
                            $priv_name = "storagePrivateData";
                        } elsif (!($name =~ m/^domain/)) {
                            $priv_name = "${name}PrivateData";
                        }
                    }

797 798 799 800 801
                    push(@args_list, "vir${type_name}Ptr $arg_name");
                    push(@setters_list, "make_nonnull_$1(&args.$arg_name, $arg_name);");
                } elsif ($args_member =~ m/^remote_uuid (\S+);/) {
                    push(@args_list, "const unsigned char *$1");
                    push(@setters_list, "memcpy(args.$1, $1, VIR_UUID_BUFLEN);");
802 803 804
                } elsif ($args_member =~ m/^remote_string (\S+);/) {
                    push(@args_list, "const char *$1");
                    push(@setters_list, "args.$1 = $1 ? (char **)&$1 : NULL;");
805 806 807 808 809 810
                } elsif ($args_member =~ m/^remote_nonnull_string (\S+)<(\S+)>;/) {
                    push(@args_list, "const char **$1");
                    push(@args_list, "unsigned int ${1}len");
                    push(@setters_list, "args.$1.${1}_val = (char **)$1;");
                    push(@setters_list, "args.$1.${1}_len = ${1}len;");
                    push(@args_check_list, { name => "\"$1\"", arg => "${1}len", limit => $2 });
811 812 813
                } elsif ($args_member =~ m/^remote_nonnull_string (\S+);/) {
                    push(@args_list, "const char *$1");
                    push(@setters_list, "args.$1 = (char *)$1;");
814 815 816 817 818
                } elsif ($args_member =~ m/^(remote_string|opaque) (\S+)<(\S+)>;/) {
                    my $type_name = $1;
                    my $arg_name = $2;
                    my $limit = $3;

819
                    if ($call->{ProcName} eq "SecretSetValue") {
820 821
                        push(@args_list, "const unsigned char *$arg_name");
                        push(@args_list, "size_t ${arg_name}len");
822
                    } elsif ($call->{ProcName} eq "DomainPinVcpu") {
823 824
                        push(@args_list, "unsigned char *$arg_name");
                        push(@args_list, "int ${arg_name}len");
825
                    } else {
826 827
                        push(@args_list, "const char *$arg_name");
                        push(@args_list, "int ${arg_name}len");
828 829
                    }

830 831 832
                    push(@setters_list, "args.$arg_name.${arg_name}_val = (char *)$arg_name;");
                    push(@setters_list, "args.$arg_name.${arg_name}_len = ${arg_name}len;");
                    push(@args_check_list, { name => "\"$arg_name\"", arg => "${arg_name}len", limit => $limit });
833 834 835
                } elsif ($args_member =~ m/^(unsigned )?(int|hyper) (\S+);/) {
                    my $type_name;
                    my $arg_name = $3;
836

837 838
                    $type_name = $1 if ($1);
                    $type_name .= $2;
839 840 841 842 843
                    $type_name =~ s/hyper/long/;

                    if ($type_name eq "int") {
                        # fix bad decisions in the xdr protocol
                        if ($arg_name eq "flags" and
844
                            $call->{ProcName} ne "DomainCoreDump" and
845 846
                            $call->{ProcName} ne "DomainGetXMLDesc" and
                            $call->{ProcName} ne "NetworkGetXMLDesc") {
847 848 849 850
                            $type_name = "unsigned int";
                        } elsif ($arg_name eq "nvcpus" and
                                 $call->{ProcName} eq "DomainSetVcpus") {
                            $type_name = "unsigned int";
851 852 853
                        } elsif ($arg_name eq "vcpu" and
                                 $call->{ProcName} eq "DomainPinVcpu") {
                            $type_name = "unsigned int";
854 855 856 857 858 859 860 861 862 863
                        }
                    }

                    if ($call->{ProcName} eq "DomainMigrateSetMaxDowntime" and
                        $arg_name eq "downtime") {
                        $type_name = "unsigned long long";
                    }

                    push(@args_list, "$type_name $arg_name");
                    push(@setters_list, "args.$arg_name = $arg_name;");
864
                } elsif ($args_member =~ m/^(\/)?\*/) {
865 866 867 868 869 870 871 872 873 874 875 876 877
                    # ignore comments
                } else {
                    die "unhandled type for argument value: $args_member";
                }

                if ($is_first_arg and $priv_src eq "conn") {
                    unshift(@args_list, "virConnectPtr conn");
                }

                $is_first_arg = 0;
            }
        }

878 879 880 881
        if (! @args_list) {
            push(@args_list, "virConnectPtr conn");
        }

882 883
        # fix priv_name for the NumOf* functions
        if ($priv_name eq "privateData" and
884 885 886
            !($call->{ProcName} =~ m/(Domains|DomainSnapshot)/) and
            ($call->{ProcName} =~ m/NumOf(Defined|Domain)*(\S+)s/ or
             $call->{ProcName} =~ m/List(Defined|Domain)*(\S+)s/)) {
887 888 889 890 891
            my $prefix = lc $2;
            $prefix =~ s/(pool|vol)$//;
            $priv_name = "${prefix}PrivateData";
        }

892 893 894 895 896
        # handle return values of the function
        my @ret_list = ();
        my $call_ret = "&ret";
        my $single_ret_var = "int rv = -1";
        my $single_ret_type = "int";
897 898 899 900 901
        my $single_ret_as_list = 0;
        my $single_ret_list_error_msg_type = "undefined";
        my $single_ret_list_name = "undefined";
        my $single_ret_list_max_var = "undefined";
        my $single_ret_list_max_define = "undefined";
902 903 904 905 906 907 908
        my $multi_ret = 0;

        if ($call->{ret} ne "void" and
            scalar(@{$call->{ret_members}}) > 1) {
            $multi_ret = 1;
        }

909
        if ($call->{ret} eq "void") {
910
            $call_ret = "NULL";
911 912
        } else {
            push(@vars_list, "$call->{ret} ret");
913 914

            foreach my $ret_member (@{$call->{ret_members}}) {
915
                if ($multi_ret) {
916 917 918 919
                    if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) {
                        push(@ret_list, "memcpy(result->$3, ret.$3, sizeof result->$3);");
                    } elsif ($ret_member =~ m/<\S+>;/ or $ret_member =~ m/\[\S+\];/) {
                        # just make all other array types fail
920 921
                        die "unhandled type for multi-return-value for " .
                            "procedure $call->{name}: $ret_member";
922 923
                    } elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+);/) {
                        push(@ret_list, "result->$3 = ret.$3;");
924
                    } else {
925 926
                        die "unhandled type for multi-return-value for " .
                            "procedure $call->{name}: $ret_member";
927
                    }
928
                } elsif ($ret_member =~ m/^remote_nonnull_string (\S+)<(\S+)>;/) {
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
                    $single_ret_as_list = 1;
                    $single_ret_list_name = $1;
                    $single_ret_list_max_var = "max$1";
                    $single_ret_list_max_define = $2;

                    my $first_arg = shift(@args_list);
                    my $second_arg;

                    if ($call->{ProcName} eq "NodeListDevices") {
                        $second_arg = shift(@args_list);
                    }

                    unshift(@args_list, "char **const $1");

                    if (defined $second_arg) {
                        unshift(@args_list, $second_arg);
                    }

                    unshift(@args_list, $first_arg);

                    push(@ret_list, "rv = ret.$1.$1_len;");
                    $single_ret_var = "int rv = -1";
                    $single_ret_type = "int";
952
                } elsif ($ret_member =~ m/^remote_nonnull_string (\S+);/) {
953 954 955
                    push(@ret_list, "rv = ret.$1;");
                    $single_ret_var = "char *rv = NULL";
                    $single_ret_type = "char *";
956
                } elsif ($ret_member =~ m/^remote_nonnull_(domain|network|storage_pool|storage_vol|node_device|interface|secret|nwfilter|domain_snapshot) (\S+);/) {
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
                    my $name = $1;
                    my $arg_name = $2;
                    my $type_name = name_to_ProcName($name);

                    if ($name eq "node_device") {
                        $priv_name = "devMonPrivateData";
                    } elsif ($name =~ m/^storage_/) {
                        $priv_name = "storagePrivateData";
                    } elsif (!($name =~ m/^domain/)) {
                        $priv_name = "${name}PrivateData";
                    }

                    if ($name eq "domain_snapshot") {
                        push(@ret_list, "rv = get_nonnull_$name(dom, ret.$arg_name);");
                    } else {
                        push(@ret_list, "rv = get_nonnull_$name($priv_src, ret.$arg_name);");
                    }

                    push(@ret_list, "xdr_free((xdrproc_t)xdr_$call->{ret}, (char *)&ret);");
                    $single_ret_var = "vir${type_name}Ptr rv = NULL";
                    $single_ret_type = "vir${type_name}Ptr";
978
                } elsif ($ret_member =~ m/^int (\S+);/) {
979 980 981 982 983 984 985 986 987 988
                    my $arg_name = $1;

                    if ($call->{ProcName} =~ m/GetAutostart$/) {
                        push(@args_list, "int *$arg_name");
                        push(@ret_list, "if ($arg_name) *$arg_name = ret.$arg_name;");
                        push(@ret_list, "rv = 0;");
                    } else {
                        push(@ret_list, "rv = ret.$arg_name;");
                    }

989 990
                    $single_ret_var = "int rv = -1";
                    $single_ret_type = "int";
991 992 993 994 995 996
                } elsif ($ret_member =~ m/^unsigned hyper (\S+);/) {
                    my $arg_name = $1;
                    push(@ret_list, "rv = ret.$arg_name;");
                    $single_ret_var = "unsigned long rv = 0";
                    $single_ret_type = "unsigned long";
                } elsif ($ret_member =~ m/^hyper (\S+);/) {
997 998 999 1000 1001 1002 1003 1004
                    my $arg_name = $1;

                    if ($call->{ProcName} =~ m/Get(Lib)?Version/) {
                        push(@args_list, "unsigned long *$arg_name");
                        push(@ret_list, "if ($arg_name) *$arg_name = ret.$arg_name;");
                        push(@ret_list, "rv = 0;");
                        $single_ret_var = "int rv = -1";
                        $single_ret_type = "int";
1005
                    } elsif ($call->{ProcName} eq "NodeGetFreeMemory") {
1006
                        push(@ret_list, "rv = ret.$arg_name;");
1007 1008 1009 1010
                        $single_ret_var = "unsigned long long rv = 0";
                        $single_ret_type = "unsigned long long";
                    } else {
                        die "unhandled type for return value: $ret_member";
1011
                    }
1012 1013
                } elsif ($ret_member =~ m/^(\/)?\*/) {
                    # ignore comments
1014
                } else {
1015 1016
                    die "unhandled type for return value for procedure " .
                        "$call->{name}: $ret_member";
1017 1018 1019 1020
                }
            }
        }

1021 1022 1023 1024 1025 1026 1027
        # select struct type for multi-return-value functions
        if ($multi_ret) {
            my $last_arg;
            my $struct_name = $call->{ProcName};
            $struct_name =~ s/Get//;

            if ($call->{ProcName} eq "DomainGetBlockInfo") {
1028 1029
                # SPECIAL: virDomainGetBlockInfo has flags parameter after
                #          the struct parameter in its signature
1030 1031 1032 1033 1034 1035 1036 1037
                $last_arg = pop(@args_list);
            }

            push(@args_list, "vir${struct_name}Ptr result");

            if (defined $last_arg) {
                push(@args_list, $last_arg);
            }
1038 1039 1040 1041
        }

        # print function
        print "\n";
1042
        print "static $single_ret_type\n";
1043 1044 1045 1046 1047 1048
        print "remote$call->{ProcName}(";

        print join(", ", @args_list);

        print ")\n";
        print "{\n";
1049
        print "    $single_ret_var;\n";
1050 1051 1052 1053 1054 1055
        print "    struct private_data *priv = $priv_src->$priv_name;\n";

        foreach my $var (@vars_list) {
            print "    $var;\n";
        }

1056 1057 1058 1059
        if ($single_ret_as_list) {
            print "    int i;\n";
        }

1060 1061 1062
        print "\n";
        print "    remoteDriverLock(priv);\n";

1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
        foreach my $args_check (@args_check_list) {
            print "\n";
            print "    if ($args_check->{arg} > $args_check->{limit}) {\n";
            print "        remoteError(VIR_ERR_RPC,\n";
            print "                    _(\"%s length greater than maximum: %d > %d\"),\n";
            print "                    $args_check->{name}, (int)$args_check->{arg}, $args_check->{limit});\n";
            print "        goto done;\n";
            print "    }\n";
        }

1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
        if ($single_ret_as_list) {
            print "\n";
            print "    if ($single_ret_list_max_var > $single_ret_list_max_define) {\n";
            print "        remoteError(VIR_ERR_RPC,\n";
            print "                    _(\"too many remote ${single_ret_list_error_msg_type}s: %d > %d\"),\n";
            print "                    $single_ret_list_max_var, $single_ret_list_max_define);\n";
            print "        goto done;\n";
            print "    }\n";
        }

1083
        if (@setters_list) {
1084
            print "\n";
1085 1086 1087 1088 1089 1090 1091 1092 1093
            print "    ";
        }

        print join("\n    ", @setters_list);

        if (@setters_list) {
            print "\n";
        }

1094 1095 1096 1097 1098
        if ($call->{ret} ne "void") {
            print "\n";
            print "    memset(&ret, 0, sizeof ret);\n";
        }

1099 1100
        print "\n";
        print "    if (call($priv_src, priv, 0, ${procprefix}_PROC_$call->{UC_NAME},\n";
1101 1102
        print "             (xdrproc_t)xdr_$call->{args}, (char *)$call_args,\n";
        print "             (xdrproc_t)xdr_$call->{ret}, (char *)$call_ret) == -1)\n";
1103 1104
        print "        goto done;\n";
        print "\n";
1105

1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
        if ($single_ret_as_list) {
            print "    if (ret.$single_ret_list_name.${single_ret_list_name}_len > $single_ret_list_max_var) {\n";
            print "        remoteError(VIR_ERR_RPC,\n";
            print "                    _(\"too many remote ${single_ret_list_error_msg_type}s: %d > %d\"),\n";
            print "                    ret.$single_ret_list_name.${single_ret_list_name}_len, $single_ret_list_max_var);\n";
            print "        goto cleanup;\n";
            print "    }\n";
            print "\n";
            print "    /* This call is caller-frees (although that isn't clear from\n";
            print "     * the documentation).  However xdr_free will free up both the\n";
            print "     * names and the list of pointers, so we have to strdup the\n";
            print "     * names here. */\n";
            print "    for (i = 0; i < ret.$single_ret_list_name.${single_ret_list_name}_len; ++i) {\n";
            print "        ${single_ret_list_name}[i] = strdup(ret.$single_ret_list_name.${single_ret_list_name}_val[i]);\n";
            print "\n";
            print "        if (${single_ret_list_name}[i] == NULL) {\n";
            print "            for (--i; i >= 0; --i)\n";
            print "                VIR_FREE(${single_ret_list_name}[i]);\n";
            print "\n";
            print "            virReportOOMError();\n";
            print "            goto cleanup;\n";
            print "        }\n";
            print "    }\n";
            print "\n";
        }

1132 1133 1134 1135
        if (@ret_list) {
            print "    ";
            print join("\n    ", @ret_list);
            print "\n";
1136 1137 1138
        }

        if ($multi_ret or !@ret_list) {
1139 1140 1141
            print "    rv = 0;\n";
        }

1142 1143 1144 1145 1146 1147
        if ($single_ret_as_list) {
            print "\n";
            print "cleanup:\n";
            print "    xdr_free((xdrproc_t)xdr_remote_$call->{name}_ret, (char *)&ret);\n";
        }

1148 1149 1150 1151 1152 1153 1154
        print "\n";
        print "done:\n";
        print "    remoteDriverUnlock(priv);\n";
        print "    return rv;\n";
        print "}\n";
    }
}