/*
* 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 "suntcp-link.h"
#include <signal.h>
/* A signal handler is a pointer to function taking int returning void. */
typedef void (*signal_handler_t)(int);
/*****************************************************************************/
int flick_read_buf(FLICK_BUFFER *out_buf, int sock)
{
/*
* Semantics of this call:
* This call should block until it gets a message.
* Reading a message:
* The first 4-byte integer received in the message will
* indicate the remaining message size. 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 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 > READ_PACKET) ? READ_PACKET
: 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 < 4) {
/* 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 < 4) {
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))
)
> READ_PACKET) ? READ_PACKET
: (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 = (ntohl(*(int *)out_buf->buf_start)
& 0x7fffffffL) + 4; /* 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))
)
> READ_PACKET) ? READ_PACKET
: (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;
}
#ifdef DEBUG
void print_buf(int size, void *data)
{
int i, j;
for (j = 0; j < 2; j++) {
for (i = 0; i < size; i++) {
if (i % 16 == 0)
printf("\n%06x: ", i);
else if (i % 4 == 0)
printf(" ");
if (j)
printf(" %c", (((char *)data)[i]) < ' ' ? ' ' : ((char *)data)[i]);
else
printf("%02x", ((char *)data)[i] & 0xff);
}
}
printf("\n");
}
#endif /* DEBUG */
int flick_write_buf(FLICK_BUFFER *buf, int socket)
{
signal_handler_t saved_sigpipe_handler;
unsigned int size = (char *)buf->buf_current - (char *)buf->buf_start;
int written = 0;
int offset = 0;
/* Set the size of the buffer */
((int *)buf->buf_start)[0] = htonl((0x80000000 | size) - 4);
#ifdef DEBUG
printf("Writing:");
print_buf(size, buf->buf_start);
#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... */
while (size > 0) {
int write_size = (size < WRITE_PACKET) ? size : WRITE_PACKET;
written = write(socket,
&((char *)buf->buf_start)[offset],
write_size);
if (written < 0)
break;
offset += written;
size -= written;
}
/* Restore the old SIGPIPE handler. */
(void) signal(SIGPIPE, saved_sigpipe_handler);
if (size > 0) {
perror("socket write failure");
/* XXX --- We used to `close(socket)' here. Gack! */
}
/* Return 1 (true) for success or 0 (false) for failure. */
return (size == 0);
}
/* End of file. */
syntax highlighted by Code2HTML, v. 0.9.1