Commits

Ivan Vučica committed 57df2e8

Work on header containing message size as well as accompanying buffering.

  • Participants
  • Parent commits aa83176

Comments (0)

Files changed (2)

 stty -F /dev/ttyS1 -ignbrk -brkint -parmrk -istrip -inlcr -igncr -icrnl -ixon -opost -echo -echonl -icanon -isig -iexten -parenb cs8
 
 echo 'launching tapper'
-./tapper /dev/ttyS1 /dev/ttyS1 &
+./tapper -v --tapper-headers /dev/ttyS1 /dev/ttyS1 &
 
 echo 'sleeping 1sec'
 sleep 1
 #include <sys/select.h>
 #include <err.h>
 
+/* for uint16_t */
+#include <stdint.h>
+
 #define ERR_CANT_TAP 1
 #define ERR_OPEN_ERR 2
 #define ERR_READ_ERR 3
 #define UIP_DRIPADDR2 2
 #define UIP_DRIPADDR3 2
 
-int primary_fd; /* a copy of the filedescriptor for tap device */
+static int primary_fd; /* a copy of the filedescriptor for tap device */
+static int enable_tuntap_headers = 0; /* CLI option - will we permit tuntap protocol headers */
+static int enable_tapper_headers = 0; /* CLI option - will we enable tapper's headers */
+static int enable_verbose = 0; /* CLI option - print out extra debug info on stderr */
+
+#define VERBOSE(x, ...) if(enable_verbose) { warnx("DEBUG: " x, ##__VA_ARGS__); }
 
 /* following function creates a tap device */
 int createTap(char *newdev)
 		err(ERR_CANT_TAP, "Could not create a TAP device");
 
 	memset(&ifr, 0, sizeof(ifr)); /* initialize the structure specifying data about net device */
-	ifr.ifr_flags=IFF_TAP|IFF_NO_PI ; /* we want a tap device, not a tun device, and we won't include tuntap driver's headers */
+	ifr.ifr_flags=IFF_TAP; /* we want a tap device, not a tun device */
+	if(!enable_tuntap_headers)
+		/* by default we won't include tuntap driver's headers */
+		ifr.ifr_flags|=IFF_NO_PI;
 
 	if((ioctl(fd, TUNSETIFF, (void*)&ifr))<0) /* tell our device what we want it to do */
 	{
 }
 
 /* when we exit we want to clean up */
-void atex()
+void atex(void)
 {
 	close(primary_fd); /* close the tap network device */
 }
+
+/* usage */
+void usage(void)
+{
+	printf("usage:\n"
+		"\n"
+		"  ./tapper [--tuntap-headers] [--tapper-headers] [-v] [stdinfile stdoutfile]\n"
+		"\n");
+	exit(0);
+}
 int main(int argc, char ** argv)
 {
 	#define BUFFERSIZE 2000 /* must be larger than MTU - 1500 */
 				to zeros so it doesn't look like we're sending a device name in*/
 	char buf[BUFFERSIZE]; /* buffer for receiving stuff */
 
-	if(argc == 3)
+	int argoff; /* argument offset; used for parsing CLI */
+	
+	for(argoff = 1; argoff < argc; argoff++)
+	{
+		if(!strcmp(argv[argoff], "-h"))
+			usage();
+		else
+		if(!strcmp(argv[argoff], "--tuntap-headers"))
+			enable_tuntap_headers = 1;
+		else
+		if(!strcmp(argv[argoff], "--tapper-headers"))
+			enable_tapper_headers = 1;
+		else
+		if(!strcmp(argv[argoff], "-v"))
+			enable_verbose = 1;
+		else
+			break;
+	}
+	
+	if(enable_tuntap_headers) VERBOSE("permitting tuntap headers");
+	if(enable_tapper_headers) VERBOSE("using tapper headers");
+
+	if(argc - argoff >= 2)
 	{
 		/* we can receive two arguments:
 		   - file we'll use for reading in place of stdin
 		fopen(argv[2], "w");
 	}
 
+
 	primary_fd=createTap(devname); /* let's create a tap device */
 
 	srand(time(NULL)+devname[3]); /* we want our ip address to depend on time, and on last
 			   the one causing select() to unblock? */
 			if(FD_ISSET(fd_int, &fds))
 			{
-				/* yay! that one has somethign to say. let's read as much as
-				   possible for our buffer. num of actually read bytes is
-				   stored in ret, unless it's -1 which is error */
-				int ret = read(fd_int, buf, BUFFERSIZE);
-				if (!ret) 
+				if(!enable_tapper_headers || fd_int != 0)
 				{
-					warnx("read(): nothing to read");
-					continue;
+					/* yay! that one has something to say. let's read as much as
+					   possible for our buffer. num of actually read bytes is
+					   stored in ret, unless it's -1 which is error */
+					size_t ret = read(fd_int, buf, BUFFERSIZE);
+					if (!ret) 
+					{
+						warnx("read(): nothing to read");
+						continue;
+					}
+					if (ret < 0) err(ERR_READ_ERR, "read(%d)", fd_int);
+			
+					/* using headers? then the fd_oth is the stdout. first,
+					   send the number of bytes we'll dispatch */
+					if(enable_tapper_headers)
+					{
+						uint16_t size = (uint16_t)htons(ret);
+
+						/* copying because we want to do one write, not two */
+						char * with_headers = malloc(sizeof(size) + ret);		
+						memcpy(with_headers, &size, sizeof(size));
+						memcpy(with_headers + sizeof(size), buf, ret);
+						if(write(fd_oth, with_headers, sizeof(size) + ret)<0)
+							err(ERR_WRITE_ERR, "write(%d)", fd_oth);
+						free(with_headers);
+					}
+					else
+					{
+						/* write ret bytes into fd_oth; that's all the bytes we read */
+						if(write(fd_oth, buf, ret)<0)
+							err(ERR_WRITE_ERR, "write(%d)", fd_oth);
+					}
 				}
-				if (ret < 0) err(ERR_READ_ERR, "read(%d)", fd_int);
-		
-				/* write ret bytes into fd_oth; that's all the bytes we read */
-				if(write(fd_oth, buf, ret)<0) 
-					err(ERR_WRITE_ERR, "write(%d)", fd_oth);
+				else
+				{
+					/* new codepath: buffer stdin until filled with enough data */
+					/* only executed for stdin, and if tapper headers are enabled */
+					static uint16_t expected_size = 0;
+					static size_t current_buffer_content_size = 0;
+					if(!expected_size)
+					{
+						int ret = read(fd_int, &expected_size, sizeof(uint16_t));
+						if(!ret)
+						{
+							warnx("read(): nothing to read");
+							continue;
+						}
+						if (ret < 0) err(ERR_READ_ERR, "read(%d)", fd_int);
+						
+						expected_size = ntohs(expected_size);
+						VERBOSE("now expecting %d bytes", expected_size);
+					}
+					else
+					{
+						size_t bytes_left = expected_size - current_buffer_content_size;
+						int ret = read(fd_int, buf + current_buffer_content_size, bytes_left);
+						if(!ret)
+						{
+							warnx("read(): nothing to read");
+							continue;
+						}
+						if (ret < 0) err(ERR_READ_ERR, "read(%d)", fd_int);
+
+						current_buffer_content_size += ret;
+						VERBOSE("received %d bytes; buffer now %d/%d", ret, current_buffer_content_size, expected_size);
+						
+						if(current_buffer_content_size == expected_size)
+						{
+							VERBOSE("got all content");
+
+							/* write ret bytes into fd_oth; that's all the bytes we read */
+							if(write(fd_oth, buf, ret)<0)
+								err(ERR_WRITE_ERR, "write(%d)", fd_oth);
+							
+							current_buffer_content_size = 0;
+							expected_size = 0;
+						}
+					}
+				}
 			}
 		}
 	}