Commit 80b3f60b authored by Chad Barb's avatar Chad Barb
Browse files

User mode frisbee server and client.

parent add78ea6
all: frisbee fromage
CFROMAGEFLAGS = -O -g -static -D_THREAD_SAFE -I/usr/local/include/pthread/linuxthreads
CFRISBEEFLAGS = -O -g
LIBS = -lz -L/usr/local/lib -llthread -llgcc_r
fromage: fromage.o f_chunker.o f_frisbee.o f_network.o f_timer.o
$(CC) $(CFROMAGEFLAGS) fromage.o f_chunker.o f_frisbee.o f_network.o f_timer.o $(LIBS) -o fromage
frisbee: server.o f_network.o f_timer.o
$(CC) $(CFRISBEEFLAGS) server.o f_network.o f_timer.o $(LIBS) -o frisbee
tidy:
-/bin/rm -f *.o
clean: tidy
-/bin/rm fromage frisbee
\ No newline at end of file
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "f_common.h"
#include "f_chunker.h"
#define BufferSlotCount 32
typedef struct {
int mb; /* -1 = none. */
int gotCount;
uchar gotBitmap[ 1024 ];
uchar data[ 1024 * 1024 ];
} BufferSlot;
BufferSlot slots[BufferSlotCount];
int totalMB;
uchar * finishedMBBitmap;
void c_init( uint sizeM, uint bufferCount )
{
int i;
/* ignoring BufferCount. */
totalMB = sizeM;
finishedMBBitmap = malloc( totalMB );
assert( finishedMBBitmap );
bzero( finishedMBBitmap, totalMB );
for (i = 0; i < BufferSlotCount; i++) {
slots[i].mb = -1;
}
}
void c_finish()
{
int i;
assert( finishedMBBitmap );
for (i = 0; i < totalMB; i++) {
if (!finishedMBBitmap[i]) {
printf("Chunker: Warning! finish called without all MBs being finished.\n");
}
}
free( finishedMBBitmap );
}
static int inProgressMB( int mb )
{
int i;
assert( mb >= 0 );
assert( mb < totalMB );
for (i = 0; i < BufferSlotCount; i++) {
if (slots[i].mb == mb) {
return 1;
}
}
return 0;
}
static int getOrAllocBufferSlotForMB( BufferSlot ** returnPointer, int mb )
{
int i;
assert( mb >= 0 );
assert( mb < totalMB );
for (i = 0; i < BufferSlotCount; i++) {
if (slots[i].mb == mb) {
*returnPointer = &(slots[i]);
return 1;
}
}
for (i = 0; i < BufferSlotCount; i++) {
if (slots[i].mb == -1) {
slots[i].mb = mb;
slots[i].gotCount = 0;
bzero( slots[i].gotBitmap, 1024 );
*returnPointer = &(slots[i]);
printf("Chunker: Starting MB %i (in slot %i)\n", mb, i );
return 1;
}
}
/* no slots */
return 0;
}
void c_addKtoM( uint kb, uchar * data )
{
int mb = kb / 1024;
int kbOffset = kb % 1024;
int byteOffset = kbOffset * 1024;
BufferSlot * bsp;
assert( mb >= 0 );
assert( mb < totalMB );
if (!finishedMBBitmap[ mb ]) {
if (getOrAllocBufferSlotForMB( &bsp, mb )) {
if (!bsp->gotBitmap[ kbOffset ]) {
bsp->gotBitmap[ kbOffset ] = 1;
memcpy( bsp->data + byteOffset, data, 1024 );
bsp->gotCount++;
}
}
}
}
int c_suggestK()
{
int i, j;
int wasAtLeastOneFree = 0;
for (i = 0; i < BufferSlotCount; i++) {
if (slots[i].mb != -1) {
if (slots[i].gotCount != 1024) {
for (j = 0; j < 1024; j++) {
if (!slots[i].gotBitmap[j]) {
return (slots[i].mb * 1024 + j);
}
}
assert( 0 ); /* shouldn't happen */
}
} else {
/* slots[i].mb == -1, ergo it's free. */
wasAtLeastOneFree = 1;
}
}
for (i = 0; i < totalMB; i++) {
if (!finishedMBBitmap[i] && !inProgressMB(i)) {
if (wasAtLeastOneFree) {
/* incomplete MB, and we *can* deal with data */
return i * 1024;
} else {
/* incomplete MB, but we cannot deal with data. */
return -1;
}
}
}
/* no incomplete MB -> done! */
return -2;
}
int c_consumeM( uint * mb, uchar ** data )
{
int i;
assert( mb );
assert( data );
for (i = 0; i < BufferSlotCount; i++) {
if ((slots[i].mb != -1) && (slots[i].gotCount == 1024)) {
*mb = slots[i].mb;
*data = slots[i].data;
return 1;
}
}
return 0;
}
void c_finishedM( uint mb )
{
int i;
assert( mb >= 0 );
assert( mb < totalMB );
finishedMBBitmap[mb] = 1;
for (i = 0; i < BufferSlotCount; i++) {
if (slots[i].mb == mb) {
printf("Chunker: Finishing MB %i (in slot %i)\n", mb, i );
slots[i].mb = -1;
return;
}
}
assert( 0 );
}
/* initialize chunker, passing the size of the file (in MB) and
the number of buffers to allocate (1 MB apiece) */
void c_init( uint sizeM, uint bufferCount );
/* close down chunker */
void c_finish();
/* suggest which kilobyte to request to help chunker on its path to glory */
int c_suggestK();
/* slip the chunker a kilobyte of data we've obtained */
void c_addKtoM( uint kb, uchar * data );
/* query for a complete megabyte;
mb will get the mb identifier, data will get a pointer to data.
returns 1 if there was something available, 0 otherwise. */
int c_consumeM( uint * mb, uchar ** data );
/* indicate that a complete megabyte has been processed and may be dumped */
void c_finishedM( uint mb );
#include <sys/types.h>
#define traceprintf printf
/* define traceprintf( X, ... ) */
#ifndef ulong
typedef unsigned long ulong;
#endif
typedef unsigned char uchar;
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <assert.h>
#include <poll.h>
#include <stdio.h>
#ifdef OSKIT
#include <oskit/startup.h>
#include <oskit/clientos.h>
#endif
#include "f_common.h"
#include "f_network.h"
#include "f_timer.h"
#include "f_chunker.h"
/* implements the following API: */
#include "frisbee.h"
#define FRISBEE_PORT 3564
/* timeout before it decides the server is dead */
#define TIMEOUT 3000
/* the minimum number of msecs between alive hint attempts */
#define ALIVE_HINT_MIN 1000
/* when added to ALIVE_HINT_MIN, the maximum number of msecs between alive hint attempts */
#define ALIVE_HINT_RANGE 2000
/* define GUNS_ABLAZING to make the client send
an alive hint immediately after it starts, rather
than holding back a while. */
#define GUNS_ABLAZING
int packetTotal;
int nextExpectedPacket;
int packetsReceivedSoFar;
int skipNextAlive;
int finishedMarker;
uint myId;
extern char version[];
extern char build_info[];
static void sendAliveHint();
static void sendGoneHint();
int frisbeeInit( const char * imageName,
unsigned int broadcastAddr )
{
#ifdef OSKIT
/* redundant calls removed.
oskit_clientos_init();
start_clock();
start_network();
*/
#endif
printf("frisbeeInit: called.\n");
/* setup my unique id */
srandomdev();
myId = random();
packetTotal = -1;
nextExpectedPacket = -1;
packetsReceivedSoFar = 0;
printf("frisbeeInit: calling n_init.\n");
n_init( FRISBEE_PORT, FRISBEE_PORT, broadcastAddr );
printf("frisbeeInit: calling t_init.\n");
t_init();
printf("frisbeeInit: calling t_setTimer.\n");
t_setTimer( ALIVE_HINT_MIN + (random() % ALIVE_HINT_RANGE) );
skipNextAlive = 0;
finishedMarker = -1;
#ifdef GUNS_ABLAZING
printf("frisbeeInit: sending alive hint.\n");
sendAliveHint();
#endif
/* XXX detect network errors, etc, and return appropriate errorcodes. */
printf("frisbeeInit: returning FRISBEE_OK\n");
return FRISBEE_OK;
}
int frisbeeInit2( const char * imageName,
const char * broadcastAddr )
{
#ifdef OSKIT
/* redundant calls removed.
oskit_clientos_init();
start_clock();
start_network();
*/
#endif
printf("frisbeeInit: called.\n");
/* setup my unique id */
srandomdev();
myId = random();
packetTotal = -1;
nextExpectedPacket = -1;
packetsReceivedSoFar = 0;
printf("frisbeeInit: calling n_init.\n");
n_initLookup( FRISBEE_PORT, FRISBEE_PORT, broadcastAddr );
printf("frisbeeInit: calling t_init.\n");
t_init();
printf("frisbeeInit: calling t_setTimer.\n");
t_setTimer( ALIVE_HINT_MIN + (random() % ALIVE_HINT_RANGE) );
skipNextAlive = 0;
finishedMarker = -1;
#ifdef GUNS_ABLAZING
printf("frisbeeInit: sending alive hint.\n");
sendAliveHint();
#endif
/* XXX detect network errors, etc, and return appropriate errorcodes. */
printf("frisbeeInit: returning FRISBEE_OK\n");
return FRISBEE_OK;
}
int frisbeeInitOld( const char * imageName,
unsigned short localPort,
const char * remoteAddr,
unsigned short remotePort )
{
#ifdef OSKIT
oskit_clientos_init();
start_clock();
start_network();
#endif
printf("frisbeeInitOld: called. =(\n");
/* setup my unique id */
srandomdev();
myId = random();
packetTotal = -1;
nextExpectedPacket = -1;
packetsReceivedSoFar = 0;
n_initLookup( localPort, remotePort, remoteAddr );
t_init();
t_setTimer( ALIVE_HINT_MIN + (random() % ALIVE_HINT_RANGE) );
skipNextAlive = 0;
finishedMarker = -1;
#ifdef GUNS_ABLAZING
sendAliveHint();
#endif
/* XXX detect network errors, etc, and return appropriate errorcodes. */
return FRISBEE_OK;
}
int frisbeeLockReadyChunk( uint * chunkId, uchar ** data )
{
return c_consumeM( chunkId, data ) ? FRISBEE_OK : FRISBEE_NO_CHUNK;
}
int frisbeeUnlockReadyChunk( uint chunkId )
{
/* XXX should check to make sure that chunkId is valid. */
c_finishedM( chunkId );
return FRISBEE_OK;
}
int frisbeeLoop()
{
Packet p;
static int done = 0;
if (done) {
return FRISBEE_DONE;
}
if (n_packetRecv( &p, TIMEOUT, NPT_DATA | NPT_POLL)) {
if ((p.type == NPT_DATA) && (packetTotal != -1)) {
/* we got data, and we already know how many packets there are */
PacketData * pd = (PacketData *)&p;
/* c_addKtoM( pd->packetId, &(pd->data)); */
c_addKtoM( pd->packetId, pd->data);
} else if (p.type == NPT_POLL) {
/* this was a poll*/
PacketPoll * pp = (PacketPoll *)&p;
/* NPT_POLL */
if (packetTotal == -1) {
/* dont know if this poll goes to us, but
* we dont already know how many packets there are,
* so there is useful information to be learned */
packetTotal = pp->packetTotal;
traceprintf("%iM to get...\n", packetTotal / 1024 );
c_init( packetTotal / 1024, 32 );
}
if (pp->address == myId) { /* XXX fix to test addressMask/address */
/* this is a poll to us */
PacketRequest pr;
/* we know the server knows about us, so don't bother sending next alive hint. */
skipNextAlive = 1;
pr.type = NPT_REQUEST;
pr.pollSequence = pp->pollSequence;
pr.packetId = c_suggestK();
if (pr.packetId == -2) {
/* we're done with the file
* XXX - shouldn't wait for a poll to decide we're done. */
sendGoneHint();
n_finish();
done = 1;
return FRISBEE_OK; /* next time we're called, we'll return a FRISBEE_DONE. */ }
if (pr.packetId == -1) {
/* there is no buffer space, so punt. */
pr.packetId = MAXUINT;
}
n_packetSend( (Packet *)&pr );
}
}
} else {
/* printf("! Couldn't hear any server.\n"); */
}
/* traceprintf("Checking if alarm went off..\n"); */
if (t_getWentOff()) {
traceprintf("Got that alarm went off...\n");
t_setTimer( ALIVE_HINT_MIN + (random() % ALIVE_HINT_RANGE) );
if (skipNextAlive == 0) {
traceprintf("Sending alive hint...\n");
sendAliveHint();
} else {
traceprintf("Skipping send of alive hint...\n");
}
skipNextAlive = 0;
}
return FRISBEE_OK;
}
int frisbeeFinish()
{
c_finish();
return FRISBEE_OK;
}
/* statics */
void sendAliveHint()
{
PacketAlive pa;
traceprintf("Sending alive hint.\n");
pa.type = NPT_ALIVE;
pa.clientId = myId;
n_packetSend( (Packet *)&pa );
}
void sendGoneHint()
{
PacketGone pg;
pg.type = NPT_GONE;
pg.clientId = myId;
n_packetSend( (Packet *)&pg );
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <assert.h>
#include <poll.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <net/route.h>
#include <sys/ioctl.h>
#include "f_common.h"
#include "f_network.h"
/* define FAKELOSS 100 */
#define OSKIT_POLL_READS
#define MCAST
#define MCAST_TTL 2
#ifdef OSKIT
/* Kludgey oskit fake poll madness.
Ick. I should bury this crap further on in the file. */
int poll( struct pollfd * x, uint y, int z ) {
/* return 1; */
fd_set fds;
FD_ZERO( &fds );
FD_SET( x->fd, &fds );
if (x->events == POLLWRNORM) {
/* a write waits forever */
return 1; /* ???! XXX is this correct? */
return select( x->fd + 1, NULL, &fds, NULL, NULL );
} else if (x->events == POLLIN) {
/* a read doesn't wait */
struct timeval tv;
#ifndef OSKIT_POLL_READS
tv.tv_sec = 0;
tv.tv_usec = 0;
#else
tv.tv_sec = z / 1000;
tv.tv_usec = (z % 1000) * 1000;
#endif
return select( x->fd + 1, &fds, NULL, NULL, &tv );
} else {
assert( 0 );
return 0;
}
}
#endif
/* define VERUCA to try and get as much i/o buffer as possible.
* A good way to hose your friend's machine.
*/
/* #define VERUCA */
#define WANTBUFFER (128 * 1024)
static int n_sizeOfType( uchar type );
/* our socket */
static int sock;
/* which port we're sending to */
static ushort nboSendPort;
/* which address (broadcast hopefully) we're sending to */
static uint nboSendAddress;
/* initialize to send, by looking up sendName and attaching the appropriate sockets */
void n_initLookup( ushort receivePort, ushort sendPort, const char * sendName )
{
struct hostent * he = gethostbyname( sendName );
if ( he == NULL ) {
printf("!!! Bad hostname \"%s\"\n", sendName );
exit(-1);
}
assert( he->h_addr_list[0] != NULL );
n_init( receivePort, sendPort, htonl( *((unsigned int *)he->h_addr_list[0])) ); /* XXX bad?? */
}
/* same initialize, only no lookup */
void n_init( ushort receivePort, ushort sendPort, uint sendAddress )
{
struct sockaddr_in name;
/* int result; */
nboSendPort = htons( sendPort );
nboSendAddress = htonl( sendAddress );
sock = socket( PF_INET, SOCK_DGRAM, 0 );