X-Git-Url: http://andersk.mit.edu/gitweb/moira.git/blobdiff_plain/ca401c434400cfda486c035370aa9a089e588230..328f0c3db5770ce36a1f7f1b7c95af26d9683927:/lib/mr_call.c diff --git a/lib/mr_call.c b/lib/mr_call.c index 903cc07f..f226e682 100644 --- a/lib/mr_call.c +++ b/lib/mr_call.c @@ -1,240 +1,225 @@ -/* - * $Source$ - * $Author$ - * $Header$ +/* $Id$ * - * Copyright (C) 1987 by the Massachusetts Institute of Technology - * - * $Log$ - * Revision 1.2 1987-05-31 22:03:37 wesommer - * Fixed numerous bugs; still shaky. + * Pass an mr_params off to the Moira server and get a reply * + * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology + * For copying and distribution information, please see the file + * . */ -#ifndef lint -static char *rcsid_sms_call_c = "$Header$"; -#endif lint +#include +#include +#include "mr_private.h" -#include "sms_private.h" +#include +#include +#include +#ifndef _WIN32 +#include +#endif /* _WIN32 */ -/* - * GDB operations to send and recieve RPC requests and replies. - */ +#ifdef HAVE_UNISTD_H +#include +#endif -static sms_abort_send() {} -static sms_abort_recv() {} - -/* - * This doesn't get called until after the actual buffered write completes. - * In a non-preflattening version of this, this would then queue the - * write of the next bunch of data. - */ +RCSID("$Header$"); -static sms_cont_send(op, hcon, arg) - OPERATION op; - HALF_CONNECTION hcon; - struct sms_params *arg; -{ - op->result = OP_SUCCESS; - db_free(arg->sms_flattened, arg->sms_size); -#ifdef notdef - db_free(arg, sizeof(struct sms_params)); -#endif notdef - return OP_COMPLETE; -} +/* Moira RPC format: -sms_start_send(op, hcon, arg) - OPERATION op; - HALF_CONNECTION hcon; - register struct sms_params *arg; -{ - int sms_size, i, len; - int *argl; - char *buf, *bp; - - /* - * This should probably be split into several routines. - * It could also probably be made more efficient (punting most - * of the argument marshalling stuff) by doing I/O directly - * from the strings. Anyone for a scatter/gather sms_send_data? - * - * that would look a lot like the uio stuff in the kernel.. hmm. - */ - - /* - * Marshall the entire data right now.. - * We are sending the version number, - * total request size, request number, - * argument count, and then each argument. - * At least for now, each argument is a string, which is - * sent as a count of bytes followed by the bytes - * (including the trailing '\0'), padded - * to a longword boundary. - */ - - sms_size = 4 * sizeof(long); - - argl = (int *)malloc(sizeof(int) * arg->sms_argc); - - /* - * For each argument, figure out how much space is needed. - */ - - for (i = 0; i < arg->sms_argc; ++i) { - if (arg->sms_argl) - argl[i] = len = arg->sms_argl[i]; - else - argl[i] = len = strlen(arg->sms_argv[i]) + 1; - sms_size += sizeof(long) + len; - sms_size += sizeof(long) * howmany(sms_size, sizeof(long)); - } - - arg->sms_flattened = buf = db_alloc(sms_size); - - bzero(arg->sms_flattened, sms_size); - - arg->sms_size = sms_size; - - /* - * This is gross. Any better suggestions, anyone? - * It should work on the RT's, since malloc is guaranteed to - * return a pointer which is aligned correctly for any data. - */ - - ((long *)buf)[0] = htonl(sms_size); - ((long *)buf)[1] = htonl(SMS_VERSION_1); - ((long *)buf)[2] = htonl(arg->sms_procno); - ((long *)buf)[3] = htonl(arg->sms_argc); - - /* - * bp is a pointer into the point in the buffer to put - * the next argument. - */ - - bp = (char *)(((long *)buf) + 4); - - for (i = 0; isms_argc; ++i) { - len = argl[i]; - *((long *)bp) = htonl(len); - bp += sizeof(long); - bcopy(arg->sms_argv[i], bp, len); - bp += sizeof(long) * howmany(len, sizeof(long)); - } - op->fcn.cont = sms_cont_send; - arg->sms_size = sms_size; - - if (gdb_send_data(hcon, arg->sms_flattened, sms_size) == OP_COMPLETE) - return sms_cont_send(op, hcon, arg); - else return OP_RUNNING; -} - -static sms_cont_recv(op, hcon, argp) - OPERATION op; - HALF_CONNECTION hcon; - sms_params **argp; + 4-byte total length (including these 4 bytes) + 4-byte version number (MR_VERSION_2 == 2) + 4-byte opcode (from client) or status (from server) + 4-byte argc + + 4-byte len, followed by null-terminated string, padded to 4-byte boundary + (the len doesn't include the padding) + ... + + (followed by more packets if status was MR_MORE_DATA) + + All numbers are in network byte order. +*/ + +int mr_do_call(struct mr_params *params, struct mr_params *reply) { - int done = FALSE; - char *cp; - int *ip; - int i; - register sms_params *arg = *argp; - - while (!done) { - switch (arg->sms_state) { - case S_RECV_START: - arg->sms_state = S_RECV_DATA; - if (gdb_receive_data(hcon, (caddr_t)&arg->sms_size, - sizeof(long)) == OP_COMPLETE) - continue; - done = TRUE; - break; - case S_RECV_DATA: - /* Should validate that length is reasonable */ - arg->sms_size = ntohl(arg->sms_size); - arg->sms_flattened = db_alloc(arg->sms_size); - arg->sms_state = S_DECODE_DATA; - bcopy((caddr_t)&arg->sms_size, arg->sms_flattened, sizeof(long)); - - if (gdb_receive_data(hcon, - arg->sms_flattened + sizeof(long), - arg->sms_size - sizeof(long)) - == OP_COMPLETE) - continue; - done = TRUE; - break; - case S_DECODE_DATA: - cp = arg->sms_flattened; - ip = (int *) cp; - /* we already got the overall length.. */ - for(i=1; i <4; i++) ip[i] = ntohl(ip[i]); - if (ip[1] != SMS_VERSION_1) - arg->sms_status = SMS_VERSION_MISMATCH; - else arg->sms_status = ip[2]; - arg->sms_argc = ip[3]; - cp += 4 * sizeof(int); - arg->sms_argv=(char **)db_alloc(arg->sms_argc *sizeof(char **)); - arg->sms_argl=(int *)db_alloc(arg->sms_argc *sizeof(int *)); - - for (i = 0; isms_argc; ++i) { - int nlen = ntohl(* (int *) cp); - cp += sizeof (long); - arg->sms_argv[i] = (char *)db_alloc(nlen); - bcopy(cp, arg->sms_argv[i], nlen); - arg->sms_argl[i]=nlen; - cp += sizeof(long) * - howmany(nlen, sizeof(long)); - } - return OP_COMPLETE; - } - } - return OP_RUNNING; + int status; + + CHECK_CONNECTED; + + status = mr_send(_mr_conn, params); + if (status == MR_SUCCESS) + status = mr_receive(_mr_conn, reply); + + if (status) + mr_disconnect(); + + return status; } - -sms_start_recv(op, hcon, argp) - OPERATION op; - HALF_CONNECTION hcon; - struct sms_params **argp; +int mr_send(int fd, struct mr_params *params) { - register sms_params *arg = *argp; - if (!arg) { - *argp = arg = (sms_params *)db_alloc(sizeof(sms_params)); + u_long length; + int written; + int i, *argl; + char *buf, *p; + + length = 16; /* length + version + opcode/status + argc */ + + if (params->mr_argl) + { + argl = params->mr_argl; + for (i = 0; i < params->mr_argc; i++) + length += 8 + argl[i]; + } + else + { + argl = malloc(params->mr_argc * sizeof(int)); + if (params->mr_argc && !argl) + return ENOMEM; + for (i = 0; i < params->mr_argc; i++) + { + argl[i] = strlen(params->mr_argv[i]) + 1; + length += 8 + argl[i]; } - arg->sms_state = S_RECV_START; - op->fcn.cont = sms_cont_recv; - return sms_cont_recv(op, hcon, argp); + } + + buf = malloc(length); + if (!buf) + { + if (!params->mr_argl) + free(argl); + return ENOMEM; + } + memset(buf, 0, length); + + putlong(buf + 4, MR_VERSION_2); + putlong(buf + 8, params->u.mr_procno); + putlong(buf + 12, params->mr_argc); + + for (i = 0, p = buf + 16; i < params->mr_argc; i++) + { + putlong(p, argl[i]); + memcpy(p += 4, params->mr_argv[i], argl[i]); + p += argl[i] + (4 - argl[i] % 4) % 4; + } + length = p - buf; + putlong(buf, length); + + written = send(fd, buf, length, 0); + free(buf); + if (!params->mr_argl) + free(argl); + + if (written != (int)length) + return MR_ABORTED; + else + return MR_SUCCESS; } -sms_do_call(parms, reply) - struct sms_params *parms; - struct sms_params **reply; +int mr_receive(int fd, struct mr_params *reply) { - if (!_sms_conn) - return SMS_NOT_CONNECTED; - - if (!_sms_send_op) - _sms_send_op = create_operation(); + int status; - if (!_sms_recv_op) - _sms_recv_op = create_operation(); + memset(reply, 0, sizeof(struct mr_params)); + do + status = mr_cont_receive(fd, reply); + while (status == -1); - gdb_inop(_sms_send_op, sms_start_send, parms, sms_abort_send); - gdb_qop(_sms_conn, CON_OUTPUT, _sms_send_op); - - gdb_inop(_sms_recv_op, sms_start_recv, reply, sms_abort_recv); - gdb_qop(_sms_conn, CON_INPUT, _sms_recv_op); + return status; +} + +/* Read some or all of a client response, without losing if it turns + * out to be malformed. Returns MR_SUCCESS on success, an error code + * on failure, or -1 if the packet hasn't been completely received + * yet. + */ - /* Block until operation done. */ - gdb_cmpo(_sms_send_op); - gdb_cmpo(_sms_recv_op); - /* Look at results */ - if (OP_STATUS(_sms_recv_op) != OP_COMPLETE) { - return SMS_ABORTED; - } - return 0; +int mr_cont_receive(int fd, struct mr_params *reply) +{ + u_long length, data; + int size, more; + char *p, *end; + int i; + + if (!reply->mr_flattened) + { + char lbuf[4]; + + size = recv(fd, lbuf, 4, 0); + if (size != 4) + return size ? MR_ABORTED : MR_NOT_CONNECTED; + getlong(lbuf, length); + if (length > 8192) + return MR_INTERNAL; + reply->mr_flattened = malloc(length); + if (!reply->mr_flattened) + return ENOMEM; + memcpy(reply->mr_flattened, lbuf, 4); + reply->mr_filled = 4; + + return -1; + } + else + getlong(reply->mr_flattened, length); + + more = recv(fd, reply->mr_flattened + reply->mr_filled, + length - reply->mr_filled, 0); + if (more == -1) + { + mr_destroy_reply(*reply); + return MR_ABORTED; + } + + reply->mr_filled += more; + + if (reply->mr_filled != length) + return -1; + + getlong(reply->mr_flattened + 4, data); + if (data != MR_VERSION_2) + { + mr_destroy_reply(*reply); + return MR_VERSION_MISMATCH; + } + + getlong(reply->mr_flattened + 8, reply->u.mr_status); + getlong(reply->mr_flattened + 12, reply->mr_argc); + if (reply->mr_argc > ((int)length - 16) / 8) + { + mr_destroy_reply(*reply); + return MR_INTERNAL; + } + reply->mr_argv = malloc(reply->mr_argc * sizeof(char *)); + reply->mr_argl = malloc(reply->mr_argc * sizeof(int)); + if (reply->mr_argc && (!reply->mr_argv || !reply->mr_argl)) + { + mr_destroy_reply(*reply); + return ENOMEM; + } + + p = (char *)reply->mr_flattened + 16; + end = (char *)reply->mr_flattened + length; + for (i = 0; i < reply->mr_argc && p + 4 <= end; i++) + { + getlong(p, reply->mr_argl[i]); + if (p + 4 + reply->mr_argl[i] > end) + break; + reply->mr_argv[i] = p + 4; + p += 4 + reply->mr_argl[i] + (4 - reply->mr_argl[i] % 4) % 4; + } + + if (i != reply->mr_argc) + { + mr_destroy_reply(*reply); + return MR_INTERNAL; + } + + return MR_SUCCESS; } -sms_destroy_reply() /*XXX not implemented yet*/ +void mr_destroy_reply(mr_params reply) { - + free(reply.mr_argl); + free(reply.mr_argv); + free(reply.mr_flattened); }