/*
* Copyright (c) 1996, 1997, 1998, 1999 The University of Utah and
* the Computer Systems Laboratory at the University of Utah (CSL).
* All rights reserved.
*
* Permission to use, copy, modify and distribute this software is hereby
* granted provided that (1) source code retains these copyright, permission,
* and disclaimer notices, and (2) redistributions including binaries
* reproduce the notices in supporting documentation.
*
* THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
* IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
* ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* CSL requests users of this software to return to csl-dist@cs.utah.edu any
* improvements that they make and grant CSL redistribution rights.
*/
#include "iiop-link.h"
#include <signal.h>
#include <assert.h>
/* A signal handler is a pointer to function taking int returning void. */
typedef void (*signal_handler_t)(int);
/*****************************************************************************/
#ifdef DEBUG
static void printbuf(FLICK_BUFFER *buf)
{
int i;
int size = buf->buf_read - buf->real_buf_start;
printf("Buffer size: %06x", size);
for (i = 0; i < size; i++) {
if (!(i & 15))
printf("\n%06x:", i);
if (!(i & 7))
printf(" ");
printf("%02x ", ((int)((char *)buf->real_buf_start)[i]) & 0xFF);
}
for (i = 0; i < size; i++) {
char c = ((char *)buf->real_buf_start)[i];
if ((c & 128) ||
!(c & ~31))
c = '?';
if (!(i & 15))
printf("\n%06x:", i);
if (!(i & 7))
printf(" ");
printf(" %c ", c);
}
printf("\n");
}
#endif /* DEBUG */
static int recv_buf(int sock, FLICK_BUFFER *out_buf)
{
/*
* Semantics of this call:
* This call should block until it gets a message.
* Reading a message:
* Each incoming message contains a GIOP header (see CORBA
* 2.0 Specification, section 12.4.1). This 12-byte header
* describes the network byte order used and the length of
* the message following the header. Once this header is
* received, we can determine the remainder of the message
* size and block until the entire message is read. In some
* cases, we may receive the next incoming message (or part
* of it) as well, and must keep track of it (for future
* calls to this function). We ensure 8-byte alignment for
* the current incoming message when we leave this function.
*/
int real_buf_size = ((char *) out_buf->real_buf_end)
- ((char *) out_buf->real_buf_start);
int bytes_read;
int test = 1;
int buf_size;
#ifdef TRACK_FRAGMENTATION
int mult = 0;
#endif /* TRACK_FRAGMENTATION */
#ifdef STATS
static int num_realign = 0;
static int num_realloc = 0;
static int num_reread = 0;
static int num_msg = 0;
num_msg++;
#endif /* STATS */
/*
* out_buf->buf_read -> how much we have already read from the socket.
* out_buf->buf_start -> start of the last message read.
* out_buf->buf_end -> end of the last message read.
*/
if ((out_buf->buf_read == out_buf->real_buf_start)/* new buffer */
|| (out_buf->buf_read <= out_buf->buf_end)) /* buf is empty */ {
out_buf->buf_start = out_buf->buf_read
= out_buf->real_buf_start;
#ifdef TRACK_FRAGMENTATION
mult++;
#endif /* TRACK_FRAGMENTATION */
if ((bytes_read = read(sock,
(char *) out_buf->buf_read,
real_buf_size)) > 0)
out_buf->buf_read = ((char *) out_buf->buf_read)
+ bytes_read;
} else {
/* go to the next message */
out_buf->buf_start = out_buf->buf_end;
bytes_read = ((char *) out_buf->buf_read)
- ((char *) out_buf->buf_start);
/*
* Flick stubs assume 8-byte alignment
* Also, realign if we don't even have the header:
* we may need as much space as we can get, so
* we might as well copy the buffer while it's
* small.
*/
if (((unsigned long) out_buf->buf_start) & 7
|| bytes_read < 12) {
/* Fix the alignment to 8-bytes */
/* (copy down to beginning of buffer) */
memcpy(out_buf->real_buf_start,
out_buf->buf_start,
bytes_read);
out_buf->buf_start = out_buf->real_buf_start;
out_buf->buf_read = ((char *) out_buf->buf_start)
+ bytes_read;
#ifdef STATS
num_realign++;
printf("Aligning buffer!\n");
#endif /* STATS */
}
}
if (bytes_read <= 0)
goto socket_error;
/* Make sure we have at least the message length */
while (bytes_read < 12) {
int new_read;
#ifdef TRACK_FRAGMENTATION
mult++;
#endif /* TRACK_FRAGMENTATION */
if ((new_read = read(sock,
(char *) out_buf->buf_read,
(real_buf_size
- (((char *) out_buf->buf_read)
- ((char *) out_buf->real_buf_start)))
)) < 0)
goto socket_error;
out_buf->buf_read = ((char *) out_buf->buf_read) + new_read;
bytes_read += new_read;
#ifdef STATS
num_reread++;
printf("Need to read more!\n");
#endif /* STATS */
}
buf_size = ((unsigned int *)out_buf->buf_start)[2];
/* endian byte swap */
if (((char *)out_buf->buf_start)[6] != ((char *)&test)[0])
buf_size = ((buf_size >> 24) & 0x000000FF) |
((buf_size >> 8) & 0x0000FF00) |
((buf_size << 8) & 0x00FF0000) |
((buf_size << 24) & 0xFF000000);
buf_size += 12; /* Offset for the header... */
out_buf->buf_end = ((char *) out_buf->buf_start) + buf_size;
/* if only partial message received */
if (out_buf->buf_end > out_buf->buf_read) {
/* if the rest of the message won't fit */
if (out_buf->buf_end > out_buf->real_buf_end) {
/* if the message is bigger than the buffer */
if (buf_size > real_buf_size) {
char *save_start = out_buf->buf_start;
out_buf->buf_start = t_malloc(char, buf_size);
if (!out_buf->buf_start) {
fprintf(stderr,
"Error: can't realloc"
" receive buffer!\n");
return 0;
}
/* copy the partial message into the
new buffer */
memcpy(out_buf->buf_start, save_start,
bytes_read);
/* free the original buffer */
free(out_buf->real_buf_start);
/* adjust real_buf and buf values
because of realloc */
real_buf_size = buf_size;
out_buf->real_buf_end /* same as buf_end */
= out_buf->buf_end
= (((char *) out_buf->buf_start)
+ buf_size);
out_buf->buf_read
= (((char *) out_buf->buf_start)
+ bytes_read);
out_buf->real_buf_start =
out_buf->buf_start;
#ifdef STATS
num_realloc++;
printf("Reallocating buffer!\n");
#endif /* STATS */
} else {
/* copy the partial message into the
beginning of the buffer */
memcpy(out_buf->real_buf_start,
out_buf->buf_start,
bytes_read);
/* adjust buf_read */
out_buf->buf_read
= (((char *) out_buf->real_buf_start)
+ bytes_read);
out_buf->buf_start
= out_buf->real_buf_start;
out_buf->buf_end
= (((char *) out_buf->buf_start)
+ buf_size);
}
}
/* read the rest of the incoming message */
do {
#ifdef TRACK_FRAGMENTATION
mult++;
#endif /* TRACK_FRAGMENTATION */
if ((bytes_read = read(sock,
(char *) out_buf->buf_read,
(real_buf_size
- (((char *) out_buf->buf_read)
- ((char *)
out_buf->real_buf_start)
))
)) < 0)
goto socket_error;
#ifdef STATS
num_reread++;
printf("Need to read more!\n");
#endif /* STATS */
out_buf->buf_read = ((char *) out_buf->buf_read)
+ bytes_read;
} /* until the whole message is read */
while (out_buf->buf_end > out_buf->buf_read);
}
#ifdef TRACK_FRAGMENTATION
if (mult > 1)
printf("Multiple (%d) reads on server!\n", mult);
#endif /* TRACK_FRAGMENTATION */
#ifdef DEBUG
printbuf(out_buf);
#endif /* DEBUG */
if (bytes_read <= 0)
goto socket_error;
#ifdef STATS
printf("Re-aligns: %d/%d %%=%d\n", num_realign, num_msg, num_realign*100/num_msg);
printf("Re-allocs: %d/%d %%=%d\n", num_realloc, num_msg, num_realloc*100/num_msg);
printf("Re-reads: %d/%d %%=%d\n", num_reread, num_msg, num_reread*100/num_msg);
#endif /* STATS */
return 1;
socket_error:
close(sock);
return 0;
}
static int send_buf(int sock, FLICK_BUFFER *in_buf)
{
signal_handler_t saved_sigpipe_handler;
int size = (char *)in_buf->buf_current - (char *)in_buf->buf_start;
int written = 0;
int offset = 0;
#ifdef TRACK_FRAGMENTATION
int mult = 0;
#endif /* TRACK_FRAGMENTATION */
#ifdef DEBUG
in_buf->buf_read = in_buf->buf_current;
printbuf(in_buf);
#endif /* DEBUG */
/* Ignore SIGPIPE: writes on a socket with no reader. */
saved_sigpipe_handler = signal(SIGPIPE, SIG_IGN);
/* I'm not sure if this while loop is necessary... */
((unsigned int *)in_buf->buf_start)[2] = size - 12;
while (size > 0) {
int amount2write = (size < PACKET_SIZE) ? size : PACKET_SIZE;
written = write(sock,
&((char *)in_buf->buf_start)[offset],
amount2write);
#ifdef TRACK_FRAGMENTATION
if (offset)
mult++;
#endif /* TRACK_FRAGMENTATION */
if (written < 0)
break;
size -= written;
offset += written;
}
/* Restore the old SIGPIPE handler. */
(void) signal(SIGPIPE, saved_sigpipe_handler);
#ifdef TRACK_FRAGMENTATION
if (mult)
printf("Multiple reads on server - %d!\n", mult);
#endif /* TRACK_FRAGMENTATION */
if (size > 0)
perror("socket write failure");
/* Return 1 (true) for success or 0 (false) for failure. */
return (size == 0);
}
/*****************************************************************************/
#if 0
int flick_buffer_contains_another_whole_message(FLICK_BUFFER *out_buf) {
#define next_buf_start (out_buf->buf_end)
/* if buf is not empty (and holds another message length) */
if ((char *)next_buf_start + 12 <= (char *)out_buf->buf_read) {
int test = 1;
int buf_size;
if (((char *)next_buf_start)[6] != ((char *)&test)[0]) {
((char *)&buf_size)[0] = ((char *)next_buf_start)[11];
((char *)&buf_size)[1] = ((char *)next_buf_start)[10];
((char *)&buf_size)[2] = ((char *)next_buf_start)[9];
((char *)&buf_size)[3] = ((char *)next_buf_start)[8];
} else {
((char *)&buf_size)[0] = ((char *)next_buf_start)[8];
((char *)&buf_size)[1] = ((char *)next_buf_start)[9];
((char *)&buf_size)[2] = ((char *)next_buf_start)[10];
((char *)&buf_size)[3] = ((char *)next_buf_start)[11];
}
buf_size += 12; /* Offset for the header... */
/* if whole message found */
return (next_buf_start + buf_size <= out_buf->buf_read);
} else {
return 0; /* return false */
}
#undef next_buf_start
}
#endif
/*****************************************************************************/
int flick_client_send_request(FLICK_TARGET obj, FLICK_BUFFER *in_buf)
{
int retries = CONNECT_RETRIES; /* Set the number of retries allowed */
int sock = obj->boa->socket_fd;
/* Check to make sure connection is still up. */
if (sock >= 0 && obj->boa->connected) {
static struct timeval nowait = { 0, 0 };
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
if (select(sock + 1, &fds, 0, 0, &nowait) > 0) {
/*
* The socket has data to be read!? This shouldn't
* occur, except when a FIN comes in to indicate the
* client has shut down its port. Thus, we close down
* our side & try again with a new connection.
*/
close(sock);
retries--;
goto MakeSocket;
}
return send_buf(sock, in_buf);
}
/* initialize the socket if not already done */
if (sock < 0) {
MakeSocket:
obj->boa->connected = 0;
obj->boa->socket_fd
= sock
= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
perror("socket");
return 0; /* return false */
}
}
/* connect to the remote host if not already done */
if (!obj->boa->connected) {
if (retries &&
(connect(sock,
(struct sockaddr *) obj->boa->ipaddr,
sizeof(*obj->boa->ipaddr)) != 0)) {
/* Figure out whether we should retry or not */
switch (errno) {
case ECONNREFUSED:
case ETIMEDOUT:
perror("connect");
fprintf(stderr, "Retrying...\n");
/* We have to close the socket and make
a new one in order to retry */
close(sock);
/* Delay for some time */
sleep(CONNECT_RETRY_DELAY);
retries--;
goto MakeSocket;
break;
default:
/* The rest are considered to be
unrecoverable errors so no retry */
perror("connect");
retries = 0;
break;
}
}
/* Figure out if we got the connect or not */
if (retries)
obj->boa->connected = 1;
else {
perror("connect");
close(sock);
obj->boa->socket_fd = -1;
return 0; /* return false */
}
}
return send_buf(sock, in_buf);
}
int flick_client_get_reply(FLICK_TARGET obj, FLICK_BUFFER *out_buf)
{
int res = recv_buf(obj->boa->socket_fd, out_buf);
if (!res)
obj->boa->socket_fd = -1;
return res;
}
int flick_server_get_request(int socket, FLICK_BUFFER *out_buf)
{
return recv_buf(socket, out_buf);
}
int flick_server_send_reply(int sock, FLICK_BUFFER *in_buf)
{
return send_buf(sock, in_buf);
}
int flick_server_send_exception(int sock,
unsigned int request_id,
const char *exception_type)
{
FLICK_BUFFER flick_buf;
int type_id_len = strlen(exception_type) + 1;
int type_id_size = (type_id_len + 3) & ~3;
char *buf = t_calloc(char,
(12 /* A `GIOP::MessageHeader'/ */
+ 12 /* Our `GIOP::ReplyHeader'/ */
+ 4 /* Our system exception. */
+ type_id_size
+ 8
));
if (!buf) {
fprintf(stderr,
"Error: can't alloc memory for "
"`flick_server_send_exception'.\n");
return 1;
}
/*
* Manufacture the `GIOP::MessageHeader'. See Section 12.4.1 of the
* CORBA 2.0 specification.
*/
buf[0] = 'G';
buf[1] = 'I';
buf[2] = 'O';
buf[3] = 'P';
buf[4] = 1;
buf[5] = 0;
buf[6] = flick_is_little_endian;
buf[7] = 1;
*((unsigned int *) &buf[8])
= (12 /* Our `GIOP::ReplyHeader' (see below). */
+ 4 /* The exception identifier length and value. */
+ type_id_size
+ 8 /* The system exception body. */
);
/*
* Manufacture the `GIOP::ReplyHeader'. See Section 12.4.2.
*/
*((unsigned int *) &buf[12]) = 0;
*((unsigned int *) &buf[16]) = request_id;
*((unsigned int *) &buf[20]) = CORBA_SYSTEM_EXCEPTION;
/*
* Encode the system exception.
*/
*((int *) &buf[24]) = type_id_len;
strncpy(&(buf[28]), exception_type, type_id_len);
*((unsigned int *) &buf[28 + type_id_size]) = 0;
*((unsigned int *) &buf[32 + type_id_size]) = CORBA_COMPLETED_NO;
/* Send this exceptional reply back to the client. */
flick_buf.buf_start = buf;
flick_buf.buf_current = buf + 36 + type_id_size;
flick_buf.buf_end = buf + 36 + type_id_size;
return send_buf(sock, &flick_buf);
}
/*****************************************************************************/
extern flick_client_table_entry *client_table;
extern unsigned int client_table_entries;
extern unsigned int max_client_table_entries;
int flick_send_request_msg(FLICK_TARGET obj,
flick_msg_t msg,
flick_invocation_id inv_id,
FLICK_PSEUDO_CLIENT cli)
{
FLICK_BUFFER buf;
unsigned int len = obj->key._length;
unsigned int siz = (len + 7) & ~3;
/*
* XXX - If we're sending this as a forwarded message,
* WE DON'T WANT TO REBUILD THE MSG HEADER!!
* However, we MUST re-encode the object key, since we will
* almost surely be forwarding it to a different object.
*/
if (((signed int) (siz + 24))
< (((char *) msg->msg) - ((char *) msg->buf))) {
msg->hdr = ((char *) msg->msg) - siz;
*((unsigned int *)msg->hdr) = len;
memcpy(((char *)msg->hdr) + 4,
obj->key._buffer, len);
/* Fill in the request header info */
msg->hdr = ((char *) msg->hdr) - 24;
flick_iiop_build_message_header(msg->hdr,
0 /* request */);
/* service context, request id, & response expected */
((unsigned int *)msg->hdr)[3] = 0;
((unsigned int *)msg->hdr)[4] = inv_id;
((unsigned int *)msg->hdr)[5] = msg->response;
} else {
/* XXX - Houston, we have a problem. */
assert(0);
msg->hdr = msg->msg;
}
((unsigned int *)msg->principal)[0]
= cli->boa->ipaddr->sin_addr.s_addr;
((unsigned short *)msg->principal)[2]
= cli->boa->ipaddr->sin_port;
((unsigned short *)msg->principal)[3]
= 0; /* ``reserved'' */
buf.buf_start = msg->hdr;
buf.buf_end
= buf.buf_current
= ((char *) msg->msg) + msg->msg_len;
/* Now set up what we need to service the reply when it comes */
if (msg->response) {
flick_client_table_entry *ent;
if (client_table_entries == max_client_table_entries) {
max_client_table_entries += 8;
client_table = t_realloc(client_table,
flick_client_table_entry,
max_client_table_entries);
}
ent = &client_table[client_table_entries++];
ent->inv_id = inv_id;
ent->client = cli;
ent->obj = obj;
ent->func = msg->func;
}
return flick_client_send_request(obj, &buf);
}
int flick_send_reply_msg(FLICK_PSEUDO_CLIENT cli,
flick_msg_t msg,
flick_invocation_id inv_id,
FLICK_TARGET obj)
{
FLICK_BUFFER buf;
FLICK_TARGET_STRUCT pseudo;
/* There's always at least room for 20 */
msg->hdr = ((char *) msg->hdr) - 20;
flick_iiop_build_message_header(msg->hdr, 1 /* reply */);
/* service context & request id */
((unsigned int *)msg->hdr)[3] = 0;
((unsigned int *)msg->hdr)[4] = inv_id;
buf.buf_start = msg->hdr;
buf.buf_end
= buf.buf_current
= ((char *) msg->msg) + msg->msg_len;
/* This is a really bad hack, but it makes it easy to reuse code.
* The only thing flick_client_send_request() uses the object for
* is to access the boa. We set the boa of a fake object to the
* boa for our client object, and then initiate a send.
* Also, please note that it may *look* like we're sending a request
* when it should be a reply, but that actually doesn't matter either
* -- we just need the connection made to the client.
*/
pseudo.boa = cli->boa;
return flick_client_send_request(&pseudo, &buf);
}
/*****************************************************************************/
int
flick_continue_request_msg(
FLICK_TARGET obj,
flick_msg_t msg,
flick_invocation_id inv_id,
FLICK_PSEUDO_CLIENT cli,
flick_request_continuer continue_func,
void *continue_data)
{
assert(!"`flick_continue_request_msg' not yet implemented!");
return 0;
}
int
flick_continue_reply_msg(
FLICK_PSEUDO_CLIENT cli,
flick_msg_t msg,
flick_invocation_id inv_id,
FLICK_TARGET obj,
flick_reply_continuer continue_func,
void *continue_data)
{
assert(!"`flick_continue_reply_msg' not yet implemented!");
return 0;
}
/* End of file. */
syntax highlighted by Code2HTML, v. 0.9.1