Commit 588c46d0 authored by David Johnson's avatar David Johnson

supafly is a synthetic application for "proving" the point that evaluating

apps/protocols that use X cpu on PlanetLab can also add network artifacts.

sfmiddleman sits in the middle as a compute-intensive proxy.  sfsender
sends the middleman n "messages" each composed of m "blocks", and can
pause for t1 and t2 times at microsecond granularity after each block send
and msg send.  sfmiddleman reads blocks and does operations on them
(default is decrypt/encrypt, can also do only encrypt), then forwards them
to all connected receivers.  You guessed it, sfreceiver connects to
sfmiddleman and reads blocks and prints timestamps.  For each op on a
block, sfmiddleman notes the number of microseconds taken by the crypto
ops, and the timestamp when it/they finished, and prints those.

There is one known bug.  I'll fix it in the morning.  If there are others,
I'll get them then too.
parent 8c719573
CC = gcc
CFLAGS += -g -lssl
all: sfmiddleman sfsender sfreceiver
sfmiddleman: sfmiddleman.c util.c crypto.c
$(CC) -o sfmiddleman $(CFLAGS) sfmiddleman.c util.c crypto.c
sfsender: sfsender.c util.c crypto.c
$(CC) -o sfsender $(CFLAGS) sfsender.c util.c crypto.c
sfreceiver: sfreceiver.c util.c
$(CC) -o sfreceiver $(CFLAGS) sfreceiver.c util.c
clean:
rm -f sfmiddleman sfsender sfreceiver
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "crypto.h"
DES_cblock *sgenkey() {
DES_cblock *retval;
retval = (DES_cblock *)malloc(sizeof(DES_cblock));
if (retval != NULL) {
DES_random_key(retval);
}
return retval;
}
DES_cblock *sgeniv() {
DES_cblock *retval;
retval = (DES_cblock *)malloc(sizeof(DES_cblock));
if (retval != NULL) {
DES_random_key(retval);
}
return retval;
}
/* note: if IV is null, don't do cbc; otherwise, do it. */
int sencrypt(unsigned char *input,unsigned char *output,
unsigned int len,DES_cblock *k1,DES_cblock *k2,
DES_cblock *iv
) {
DES_key_schedule s1,s2;
int i;
if (len%8 != 0) {
return -1;
}
/* the idea is to process the keys each time to keep them out of memory
* if possible (besides, it's easier)
*/
DES_set_key_checked(k1,&s1);
DES_set_key_checked(k2,&s2);
if (iv == NULL) {
/* actually encrypt, now */
//printf("%d\n",len/8);
for (i = 0; i < len; i+=8) {
//printf("encrypt block %d\n",i);
DES_ecb2_encrypt(input+i,output+i,&s1,&s2,DES_ENCRYPT);
}
}
else {
DES_ede2_cbc_encrypt(input,output,len,&s1,&s2,iv,DES_ENCRYPT);
}
return 0;
}
int sdecrypt(unsigned char *input,unsigned char *output,
unsigned int len,DES_cblock *k1,DES_cblock *k2,
DES_cblock *iv
) {
DES_key_schedule s1,s2;
int i;
if (len%8 != 0) {
return -1;
}
/* the idea is to process the keys each time to keep them out of memory
* if possible (besides, it's easier)
*/
DES_set_key_checked(k1,&s1);
DES_set_key_checked(k2,&s2);
//printf("blah2\n");
if (iv == NULL) {
//printf("blah3\n");
/* actually encrypt, now */
for (i = 0; i < len; i+=8) {
//printf("decrypt block %d\n",i);
DES_ecb2_encrypt(input+i,output+i,&s1,&s2,DES_DECRYPT);
}
}
else {
//printf("blah4\n");
DES_ede2_cbc_encrypt(input,output,len,&s1,&s2,iv,DES_DECRYPT);
}
return 0;
}
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#include <openssl/rand.h>
#include <openssl/des.h>
DES_cblock *sgenkey();
DES_cblock *sgeniv();
/* note: if IV is null, don't do cbc; otherwise, do it. */
int sencrypt(unsigned char *input,unsigned char *output,
unsigned int len,DES_cblock *k1,DES_cblock *k2,
DES_cblock *iv);
int sdecrypt(unsigned char *input,unsigned char *output,
unsigned int len,DES_cblock *k1,DES_cblock *k2,
DES_cblock *iv);
#endif /* __CRYPTO_H__ */
#ifndef __DEFS_H__
#define __DEFS_H__
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
/** sane systems honor this as 32 bits regardless */
/**
* each sent packet group (allowing for app/ip frag) must prefix a new
* unit with the length of crap being sent. This might be useful...
*/
typedef uint32_t slen_t;
#define MIDDLEMAN_SEND_CLIENT_PORT 6878
#define MIDDLEMAN_RECV_CLIENT_PORT 6888
#define MIDDLEMAN_MAX_CLIENTS 32
#define MAX_NAME_LEN 255
#endif /* __DEFS_H__ */
This diff is collapsed.
#include <stdio.h>
#include "defs.h"
#include "crypto.h"
/**
* globals
*/
char *optarg;
int optind,opterr,optopt;
/** -s <bytes>*/
int block_size = 4096;
/** -m <middleman hostname> */
char *middleman_host = "localhost";
/** -M <middleman hostport> */
short middleman_port = MIDDLEMAN_RECV_CLIENT_PORT;
int debug = 0;
char *deadbeef = "deadbeef";
/**
* functions
*/
void usage(char *bin) {
fprintf(stdout,
"USAGE: %s -scCmMud (option defaults in parens)\n",
bin
);
}
void parse_args(int argc,char **argv) {
int c;
char *ep = NULL;
while ((c = getopt(argc,argv,"s:m:M:ud")) != -1) {
switch(c) {
case 's':
block_size = (int)strtol(optarg,&ep,10);
if (ep == optarg) {
usage(argv[0]);
exit(-1);
}
break;
case 'u':
usage(argv[0]);
exit(0);
case 'd':
++debug;
break;
default:
break;
}
}
/** arg check */
if (block_size % 8 != 0) {
fprintf(stderr,"block_size must be divisible by 8!\n");
exit(-1);
}
return;
}
int main(int argc,char **argv) {
char *buf,*outbuf;
struct sockaddr_in recv_sa;
int recv_sock;
int i;
int retval;
int bytesRead;
int blocksRead = 0;
struct timeval t1;
parse_args(argc,argv);
/* initialize ourself... */
//srand(time(NULL));
/* grab some buf! */
if ((buf = (char *)malloc(sizeof(char)*block_size)) == NULL) {
efatal("no memory for data buf");
}
if ((outbuf = (char *)malloc(sizeof(char)*block_size)) == NULL) {
efatal("no memory for output data buf");
}
/* fill with deadbeef */
//for (i = 0; i < block_size; i += 8) {
//memcpy(&buf[i],deadbeef,8);
//}
/* setup the sockaddrs */
if ((retval = fill_sockaddr(middleman_host,
middleman_port,
&recv_sa)) != 0) {
if (retval == -1) {
fatal("bad port");
}
else {
efatal("host lookup failed");
}
}
/* startup recv client... */
if ((recv_sock = socket(PF_INET,SOCK_STREAM,0)) == -1) {
efatal("could not get recv socket");
}
/* connect to the middleman if we can... */
if (connect(recv_sock,
(struct sockaddr *)&recv_sa,
sizeof(struct sockaddr_in)) < 0) {
efatal("could not connect to middleman");
}
/**
* read blocks forever, noting times at which a block was completely read.
*/
while (1) {
bytesRead = 0;
while (bytesRead < block_size) {
retval = read(recv_sock,buf,block_size);
if (retval < 0) {
if (errno == ECONNRESET) {
/* middleman must've dumped out. */
efatal("middleman appears to have disappeared");
}
else if (errno == EAGAIN) {
;
}
else {
ewarn("weird");
}
}
else {
bytesRead += retval;
}
}
gettimeofday(&t1,NULL);
fprintf(stdout,
"INFO: read %d bytes (a block) at %.6f\n",
block_size,
t1.tv_sec + t1.tv_usec / 1000000.0f);
}
/* never get here... */
exit(0);
}
#include <stdio.h>
#include "defs.h"
#include "crypto.h"
/**
* globals
*/
char *optarg;
int optind,opterr,optopt;
/** -s <bytes>*/
int block_size = 4096;
/** -c <num> */
int block_count = 1024;
/** -C <num> */
int msg_count = 1;
/** -p <microseconds> */
long block_pause_us = 1000;
/** -P <microseconds> */
long msg_pause_us = 5000000;
/** -m <middleman hostname> */
char *middleman_host = "localhost";
/** -M <middleman hostport> */
short middleman_port = MIDDLEMAN_SEND_CLIENT_PORT;
int debug = 0;
char *deadbeef = "deadbeef";
/**
* functions
*/
void usage(char *bin) {
fprintf(stdout,
"USAGE: %s -scCpPmMud (option defaults in parens)\n",
bin
);
}
void parse_args(int argc,char **argv) {
int c;
char *ep = NULL;
while ((c = getopt(argc,argv,"s:c:C:p:P:m:M:ud")) != -1) {
switch(c) {
case 's':
block_size = (int)strtol(optarg,&ep,10);
if (ep == optarg) {
usage(argv[0]);
exit(-1);
}
break;
case 'c':
block_count = (int)strtol(optarg,&ep,10);
if (ep == optarg) {
usage(argv[0]);
exit(-1);
}
break;
case 'C':
msg_count = (int)strtol(optarg,&ep,10);
if (ep == optarg) {
usage(argv[0]);
exit(-1);
}
break;
case 'p':
block_pause_us = strtol(optarg,&ep,10);
if (ep == optarg) {
usage(argv[0]);
exit(-1);
}
break;
case 'P':
msg_pause_us = strtol(optarg,&ep,10);
if (ep == optarg) {
usage(argv[0]);
exit(-1);
}
break;
case 'u':
usage(argv[0]);
exit(0);
case 'd':
++debug;
break;
default:
break;
}
}
/** arg check */
if (block_size % 8 != 0) {
fprintf(stderr,"block_size must be divisible by 8!\n");
exit(-1);
}
return;
}
int main(int argc,char **argv) {
char *buf,*outbuf;
struct sockaddr_in send_sa;
int send_sock;
int remaining_block_count;
int remaining_msg_count;
int i;
int retval;
int bytesWritten;
parse_args(argc,argv);
remaining_block_count = block_count;
remaining_msg_count = msg_count;
/* initialize ourself... */
srand(time(NULL));
/* grab some buf! */
if ((buf = (char *)malloc(sizeof(char)*block_size)) == NULL) {
efatal("no memory for data buf");
}
if ((outbuf = (char *)malloc(sizeof(char)*block_size)) == NULL) {
efatal("no memory for output data buf");
}
/* fill with deadbeef */
for (i = 0; i < block_size; i += 8) {
memcpy(&buf[i],deadbeef,8);
}
/* setup the sockaddrs */
if ((retval = fill_sockaddr(middleman_host,
middleman_port,
&send_sa)) != 0) {
if (retval == -1) {
fatal("bad port");
}
else {
efatal("host lookup failed");
}
}
/* startup send client... */
if ((send_sock = socket(PF_INET,SOCK_STREAM,0)) == -1) {
efatal("could not get send socket");
}
/* connect to the middleman if we can... */
if (connect(send_sock,
(struct sockaddr *)&send_sa,
sizeof(struct sockaddr_in)) < 0) {
efatal("could not connect to middleman");
}
/* heh, we don't do encryption! that way, if the middleman
* does a decrypt/encrypt with the same keys/iv, they should forward
* deadbeef to the sfreceiver. nasty, but whatever. provides a little
* testing.
*/
while (remaining_msg_count > 0) {
/* prepare to send a msg... */
while (remaining_block_count > 0) {
/* send a block */
bytesWritten = 0;
while (bytesWritten < block_size) {
retval = write(send_sock,buf,block_size - bytesWritten);
if (retval < 0) {
if (errno == EPIPE) {
efatal("while writing to middleman");
}
else {
ewarn("while writing to middleman");
}
}
else {
bytesWritten += retval;
}
}
--remaining_block_count;
if (remaining_block_count % 8 == 0) {
fprintf(stdout,
"INFO: %d blocks remaining in msg %d\n",
remaining_block_count,
msg_count - remaining_msg_count);
}
/* interblock sleep time */
if (block_pause_us > 0) {
if (usleep(block_pause_us) < 0) {
ewarn("usleep after block failed");
}
}
}
--remaining_msg_count;
fprintf(stdout,
"INFO: only %d msgs remaining\n",
remaining_msg_count);
/* intermsg sleep time */
if (msg_pause_us > 0 && remaining_msg_count > 0) {
if (usleep(msg_pause_us) < 0) {
ewarn("usleep after msg failed");
}
}
}
fprintf(stdout,"Done, exiting.\n");
exit(0);
}
#include "util.h"
#include "defs.h"
void efatal(char *msg) {
fprintf(stdout,"%s: %s\n",msg,strerror(errno));
exit(-1);
}
void fatal(char *msg) {
fprintf(stdout,"%s\n",msg);
exit(-2);
}
void ewarn(char *msg) {
fprintf(stdout,"WARNING: %s: %s\n",msg,strerror(errno));
}
void warn(char *msg) {
fprintf(stdout,"WARNING: %s\n",msg);
}
int fill_sockaddr(char *hostname,int port,struct sockaddr_in *new_sa) {
struct hostent *host_ptr;
if (port < 1) {
return -2;
}
new_sa->sin_family = AF_INET;
new_sa->sin_port = htons((short) port);
if (hostname != NULL && strlen(hostname) > 0) {
host_ptr = gethostbyname(hostname);
if (!host_ptr) {
return -3;
}
memcpy((char *) &new_sa->sin_addr.s_addr,
(char *) host_ptr->h_addr_list[0],
host_ptr->h_length);
}
else {
new_sa->sin_addr.s_addr = INADDR_ANY;
}
return 0;
}
#ifndef __UTIL_H__
#define __UTIL_H__
#include <netinet/in.h>
/**
* ugh, this is all very catch-all.
*
* ANYTHING that I might in more than one entity goes here.
*/
void efatal(char *msg);
void fatal(char *msg);
void ewarn(char *msg);
void warn(char *msg);
int fill_sockaddr(char *hostname,int port,struct sockaddr_in *new_sa);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment