From ed2a024d47072b167bc0836a997b8ab81719226d Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Fri, 17 Jun 2005 13:45:40 +0000 Subject: [PATCH] Select test-set imported from the minix contributions, with permission to modify and distribute from Jose Manuel Gomez, the author (jmgomez@linuxmail.org). --- test/select/Makefile | 38 ++++++++ test/select/speed.c | 60 ++++++++++++ test/select/test00.c | 46 +++++++++ test/select/test01.c | 72 ++++++++++++++ test/select/test02.c | 112 ++++++++++++++++++++++ test/select/test03.c | 136 +++++++++++++++++++++++++++ test/select/test04_cli.c | 149 +++++++++++++++++++++++++++++ test/select/test04_srv.c | 135 ++++++++++++++++++++++++++ test/select/test05_cli.c | 167 +++++++++++++++++++++++++++++++++ test/select/test05_srv.c | 198 +++++++++++++++++++++++++++++++++++++++ test/select/test06_cli.c | 162 ++++++++++++++++++++++++++++++++ test/select/test06_srv.c | 128 +++++++++++++++++++++++++ test/select/test07_cli.c | 182 +++++++++++++++++++++++++++++++++++ test/select/test07_srv.c | 138 +++++++++++++++++++++++++++ test/select/test08_cli.c | 183 ++++++++++++++++++++++++++++++++++++ test/select/test08_srv.c | 146 +++++++++++++++++++++++++++++ test/select/test09.c | 63 +++++++++++++ test/select/test10.c | 70 ++++++++++++++ test/select/test11.c | 162 ++++++++++++++++++++++++++++++++ test/select/test12.c | 39 ++++++++ test/select/test13a.c | 56 +++++++++++ test/select/test13b.c | 67 +++++++++++++ 22 files changed, 2509 insertions(+) create mode 100644 test/select/Makefile create mode 100644 test/select/speed.c create mode 100644 test/select/test00.c create mode 100644 test/select/test01.c create mode 100644 test/select/test02.c create mode 100644 test/select/test03.c create mode 100755 test/select/test04_cli.c create mode 100755 test/select/test04_srv.c create mode 100644 test/select/test05_cli.c create mode 100755 test/select/test05_srv.c create mode 100755 test/select/test06_cli.c create mode 100755 test/select/test06_srv.c create mode 100755 test/select/test07_cli.c create mode 100755 test/select/test07_srv.c create mode 100755 test/select/test08_cli.c create mode 100755 test/select/test08_srv.c create mode 100644 test/select/test09.c create mode 100644 test/select/test10.c create mode 100644 test/select/test11.c create mode 100644 test/select/test12.c create mode 100644 test/select/test13a.c create mode 100644 test/select/test13b.c diff --git a/test/select/Makefile b/test/select/Makefile new file mode 100644 index 000000000..1803aac9e --- /dev/null +++ b/test/select/Makefile @@ -0,0 +1,38 @@ +# Makefile for the tests + +CC = exec cc +CFLAGS = -Wall -D_MINIX -D_POSIX_SOURCE + +PROG = speed test00 test01 test02 test03 test04_srv test04_cli test05_srv \ + test05_cli test06_srv test06_cli test07_srv test07_cli test08_srv \ + test08_cli test09 test10 test11 test12 test13a test13b + +all: $(PROG) + +$(PROG): + $(CC) $(CFLAGS) -o $@ $@.c + +clean: + /usr/bin/rm -f *.o $(PROG) + +speed: speed.c +test00: test00.c +test01: test01.c +test02: test02.c +test03: test03.c +test04_cli: test04_cli.c +test04_srv: test04_srv.c +test05_cli: test05_cli.c +test05_srv: test05_srv.c +test06_cli: test06_cli.c +test06_srv: test06_srv.c +test07_cli: test07_cli.c +test07_srv: test07_srv.c +test08_cli: test08_cli.c +test08_srv: test08_srv.c +test09: test09.c +test10: test10.c +test11: test11.c +test12: test12.c +test13a: test13a.c +test13b: test13b.c diff --git a/test/select/speed.c b/test/select/speed.c new file mode 100644 index 000000000..cf0d36a3c --- /dev/null +++ b/test/select/speed.c @@ -0,0 +1,60 @@ +/* + * Test name: speed.c + * + * Objetive: Test the time it takes for select to run. + * + * Description: This tests creates a number of udp connections and performs + * a select call waiting on them for reading with timeout of 0. + * This is done 10,000 thousands of times and then the average time it takes + * is computed + * + * Jose M. Gomez + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define NUMBER 12 + +void main(void) { + char *udp_device; + int fd[NUMBER]; + fd_set fds_write; + struct timeval timeout; + time_t start_time, end_time; + int i; + + FD_ZERO(&fds_write); + for (i = 0; i < NUMBER; i++) { + fd[i] = open("/dev/tty", O_RDWR); + if (fd[i] < 0) { + fprintf(stderr, "Error opening tty %d\n", i); + exit(-1); + } + FD_SET(fd[i], &fds_write); + } + + printf("Select will send 1 msg to terminal and %d to inet: \n", NUMBER); + timeout.tv_sec = 0; + timeout.tv_usec = 0; + /* get initial time */ + start_time = time(NULL); + for (i = 0; i < 32000; i++) { + select(NUMBER + 4, NULL, &fds_write, NULL, &timeout); + } + /* get final time */ + end_time = time(NULL); + printf("The select call took on average: %f\n", (float)(end_time - start_time) / 32000.0); + for (i = 0; i < NUMBER; i++) { + close(fd[i]); + } +} diff --git a/test/select/test00.c b/test/select/test00.c new file mode 100644 index 000000000..c49fb89d9 --- /dev/null +++ b/test/select/test00.c @@ -0,0 +1,46 @@ +/* + * Test name: test00.c + * + * Objetive: The purpose of this test is to make sure that the bitmap + * manipulation macros work without problems. + * + * Description: This tests first fills a fd_set bit by bit, and shows it, then + * it clears the fd_set bit by bit as well. + * + * Jose M. Gomez + */ + +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + fd_set fds; + int i,j; + + FD_ZERO(&fds); + for (i=0;i +#include +#include +#include +#include + +#define SECONDS 3 +#define USECONDS 3000000L + +int main(void) { + int r; + time_t start, end; /* variables for timing */ + struct timeval timeout; /* timeout structure */ + + /* Set timeout for 3 seconds */ + timeout.tv_sec = SECONDS; + timeout.tv_usec = 0; + printf("Sleeping now for %d seconds...\n", SECONDS); + /* Record time before starting */ + start = time(NULL); + r = select(0, NULL, NULL, NULL, &timeout); + printf("select return code: %d error: %s\n", + r, strerror(errno)); + end = time(NULL); + printf("For a timeout with select of %d seconds, it took %d actual seconds\n", + SECONDS, end-start); + + /* Set timeout for 3 seconds , but specified in microseconds */ + + timeout.tv_sec = 0; + timeout.tv_usec = USECONDS; + printf("\n***************************\n"); + printf("Sleeping now for %ld microseconds...\n", USECONDS); + /* Record time before starting */ + start = time(NULL); + r = select(0, NULL, NULL, NULL, &timeout); + printf("select return code: %d error: %s\n", + r, strerror(errno)); + end = time(NULL); + printf("For a timeout with select of %ld useconds, it took %d actual seconds\n", + USECONDS, end-start); + + /* Set timeout for 1.5 seconds, but specified in microseconds */ + + timeout.tv_sec = 0; + timeout.tv_usec = USECONDS/2; + printf("\n***************************\n"); + printf("Sleeping now for %ld microseconds...\n", USECONDS/2); + /* Record time before starting */ + start = time(NULL); + r = select(0, NULL, NULL, NULL, &timeout); + printf("select return code: %d error: %s\n", + r, strerror(errno)); + end = time(NULL); + printf("For a timeout with select of %ld useconds, it took %d actual seconds\n", + USECONDS/2, end-start); + return 0; +} diff --git a/test/select/test02.c b/test/select/test02.c new file mode 100644 index 000000000..93a2b2364 --- /dev/null +++ b/test/select/test02.c @@ -0,0 +1,112 @@ +/* + * Test name: test02.c + * + * Objetive: The purpose of this test is to make sure that select works + * when working with files. + * + * Description: This tests first creates six dummy files with different + * modes and performs select calls on them evaluating the input and resulting + * bitmaps. + * + * Jose M. Gomez + */ + +#include +#include +#include +#include +#include +#include +#include + +void dump_fdset(fd_set *set) { + int i; + for (i = 0; i < OPEN_MAX; i++) + if (FD_ISSET(i, set)) + printf(" %d->1 ", i); + else + printf(" %d->0 ", i); + printf("\n"); +} + +void main(void) { + int fd1, fd2, fd3, fd4, fd5, fd6; /* file descriptors of files */ + fd_set fds_read, fds_write; + int retval; + + /* Creates the dummy files with different modes */ + fd1 = open("dummy1.txt", O_CREAT | O_RDONLY); + if (fd1 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd2 = open("dummy2.txt", O_CREAT | O_RDONLY); + if (fd2 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd3 = open("dummy3.txt", O_CREAT | O_WRONLY); + if (fd3 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd4 = open("dummy4.txt", O_CREAT | O_WRONLY); + if (fd4 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd5 = open("dummy5.txt", O_CREAT | O_RDWR); + if (fd5 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd6 = open("dummy6.txt", O_CREAT | O_RDWR); + if (fd6 < 0) { + perror("Error opening file"); + exit(-1); + } + + /* Create the fd_set structures */ + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_SET(fd1, &fds_read); /* fd1 => O_RDONLY */ + FD_SET(fd2, &fds_read); /* fd2 => O_RDONLY */ + FD_SET(fd3, &fds_write); /* fd3 => O_WRONLY */ + FD_SET(fd4, &fds_write); /* fd4 => O_WRONLY */ + FD_SET(fd5, &fds_read); /* fd5 => O_RDWR */ + FD_SET(fd5, &fds_write); /* fd5 => O_RDWR */ + FD_SET(fd6, &fds_read); /* fd6 => O_RDWR */ + FD_SET(fd6, &fds_write); /* fd6 => O_RDWR */ + + printf("* Dump INPUT fds_read:\n"); + dump_fdset(&fds_read); + printf("* Dump INPUT fds_write:\n"); + dump_fdset(&fds_write); + + retval=select(9, &fds_read, &fds_write, NULL, NULL); + printf("\n***********************\n"); + printf("After select: \n"); + printf("Return value: %d\n", retval); + printf("* Dump RESULTING fds_read:\n"); + dump_fdset(&fds_read); + printf("* Dump RESULTING fds_write:\n"); + dump_fdset(&fds_write); + /* close and delete dummy files */ + close(fd1); + close(fd2); + close(fd3); + close(fd4); + close(fd5); + close(fd6); + unlink("dummy1.txt"); + unlink("dummy2.txt"); + unlink("dummy3.txt"); + unlink("dummy4.txt"); + unlink("dummy5.txt"); + unlink("dummy6.txt"); +} diff --git a/test/select/test03.c b/test/select/test03.c new file mode 100644 index 000000000..98838ad3b --- /dev/null +++ b/test/select/test03.c @@ -0,0 +1,136 @@ +/* + * Test name: test02.c + * + * Objetive: The purpose of this test is to make sure that select works + * when working with files. + * + * Description: This test shows more cases than in test02.c, where every + * descriptor is ready. Here in one select call only half of the fd's will + * be ready and in the next one none of them will be ready. + * + * Jose M. Gomez + */ + +#include +#include +#include +#include +#include +#include +#include + +void dump_fdset(fd_set *set) { + int i; + for (i = 0; i < OPEN_MAX; i++) + if (FD_ISSET(i, set)) + printf(" %d ", i); + printf("\n"); +} + +void main(void) { + int fd1, fd2, fd3, fd4, fd5, fd6; /* file descriptors of files */ + fd_set fds_read, fds_write; /* bit maps */ + struct timeval timeout; /* timeout */ + int retval; /* ret value */ + + /* Creates the dummy files with different modes */ + fd1 = open("dummy1.txt", O_CREAT | O_RDONLY); + if (fd1 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd2 = open("dummy2.txt", O_CREAT | O_RDONLY); + if (fd2 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd3 = open("dummy3.txt", O_CREAT | O_WRONLY); + if (fd3 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd4 = open("dummy4.txt", O_CREAT | O_WRONLY); + if (fd4 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd5 = open("dummy5.txt", O_CREAT | O_RDWR); + if (fd5 < 0) { + perror("Error opening file"); + exit(-1); + } + + fd6 = open("dummy6.txt", O_CREAT | O_RDWR); + if (fd6 < 0) { + perror("Error opening file"); + exit(-1); + } + + /* Create the fd_set structures */ + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_SET(fd1, &fds_write); /* fd1 => O_RDONLY */ + FD_SET(fd2, &fds_write); /* fd2 => O_RDONLY */ + FD_SET(fd3, &fds_read); /* fd3 => O_WRONLY */ + FD_SET(fd4, &fds_read); /* fd4 => O_WRONLY */ + FD_SET(fd5, &fds_read); /* fd5 => O_RDWR */ + FD_SET(fd5, &fds_write); /* fd5 => O_RDWR */ + FD_SET(fd6, &fds_read); /* fd6 => O_RDWR */ + FD_SET(fd6, &fds_write); /* fd6 => O_RDWR */ + + printf("* Dump INPUT fds_read:\n"); + dump_fdset(&fds_read); + printf("* Dump INPUT fds_write:\n"); + dump_fdset(&fds_write); + + retval=select(9, &fds_read, &fds_write, NULL, NULL); + printf("\n***********************\n"); + printf("After select: \n"); + printf("Return value: %d\n", retval); + printf("* Dump RESULTING fds_read:\n"); + dump_fdset(&fds_read); + printf("* Dump RESULTING fds_write:\n"); + dump_fdset(&fds_write); + + /* make a select call where none of them are ready (don't use fd5 and fd6) */ + + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_SET(fd1, &fds_write); /* fd1 => O_RDONLY */ + FD_SET(fd2, &fds_write); /* fd2 => O_RDONLY */ + FD_SET(fd3, &fds_read); /* fd3 => O_WRONLY */ + FD_SET(fd4, &fds_read); /* fd4 => O_WRONLY */ + + + /* make a select call where none of them are ready (don't use fd5 and fd6) */ + /* create a timeout as well */ + timeout.tv_sec = 5; + timeout.tv_usec = 0; + retval=select(7, &fds_read, &fds_write, NULL, NULL); + printf("\n***********************\n"); + printf("After select: \n"); + printf("Return value: %d\n", retval); + printf("* Dump RESULTING fds_read:\n"); + dump_fdset(&fds_read); + printf("* Dump RESULTING fds_write:\n"); + dump_fdset(&fds_write); + + + /* close and delete dummy files */ + close(fd1); + close(fd2); + close(fd3); + close(fd4); + close(fd5); + close(fd6); + unlink("dummy1.txt"); + unlink("dummy2.txt"); + unlink("dummy3.txt"); + unlink("dummy4.txt"); + unlink("dummy5.txt"); + unlink("dummy6.txt"); +} diff --git a/test/select/test04_cli.c b/test/select/test04_cli.c new file mode 100755 index 000000000..8bf41fc95 --- /dev/null +++ b/test/select/test04_cli.c @@ -0,0 +1,149 @@ +/* + * Test name: test04_cli.c + * + * Objective: Test a simple UDP client + * + * Description: Implements a simple echo client using the UDP protocol. First + * it waits until it is possible to write (which is always). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6000L + +/* Type for received data */ +typedef struct +{ + udp_io_hdr_t header; + char data[1024]; +} udp_buffer_t; + + +int udp_conf(char *host, long port, udp_io_hdr_t *header) +{ + /* configures UDP connection */ + char *udp_device; + struct hostent *hp; + int netfd; + nwio_udpopt_t udpopt; + ipaddr_t dirhost; + int result; + + /* get host address */ + if ((hp = gethostbyname(host)) == (struct hostent*) NULL) + { + fprintf(stderr,"Unknown host\n"); + return(-1); + } + memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); + + /* Get UDP device */ + if (( udp_device = getenv("UDP_DEVICE") ) == NULL) + udp_device = UDP_DEVICE; + + /* Get UDP connection */ + if ((netfd = open(udp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening UDP device\n"); + return -1; + } + + /* Configure UDP connection */ + udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC | NWUO_DI_BROAD + | NWUO_RP_SET | NWUO_RA_SET | NWUO_RWDATALL | NWUO_DI_IPOPT; + udpopt.nwuo_remaddr = dirhost; + udpopt.nwuo_remport = (udpport_t) htons(port); + + if ((result = ioctl(netfd, NWIOSUDPOPT, &udpopt) ) <0) + { + fprintf(stderr, "Error establishing communication\n"); + printf("Error: %d\n",result); + close(netfd); + return -1; + } + + /* Get configuration for UDP comm */ + if ((result = ioctl(netfd, NWIOGUDPOPT, &udpopt) ) < 0) + { + fprintf(stderr,"Error getting configuration\n"); + printf("Error: %d\n", result); + close(netfd); + return -1; + } + + header->uih_src_addr = udpopt.nwuo_locaddr; + header->uih_dst_addr = udpopt.nwuo_remaddr; + header->uih_src_port = udpopt.nwuo_locport; + header->uih_dst_port = udpopt.nwuo_remport; + + return netfd; +} + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + udp_buffer_t buffer_send, buffer_rec; + fd_set fds_write; + int ret; + + /* Check parameters */ + if (argc !=2) { + fprintf(stderr,"Usage: %s host\n", argv[0]); + exit(-1); + } + + if ((fd = udp_conf(argv[1], PORT, &buffer_send.header) ) < 0) + exit(-1); + + /* init fd_set */ + FD_ZERO(&fds_write); + FD_SET(fd, &fds_write); + + while (1) + { + /* Wait until it is possible to write with select */ + + ret = select(4, NULL, &fds_write, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "Error on select waiting for write: %d\n", errno); + exit(-1); + } + if (!FD_ISSET(fd, &fds_write)) { + fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); + exit(-1); + } + + /* Get a string and send it */ + printf("Ready to write...\n"); + printf("Send data: "); + gets(buffer_send.data); + write(fd, &buffer_send, sizeof(udp_buffer_t)); + + /* If data sent is exit then break */ + if (!strcmp(buffer_send.data,"exit")) + break; + + /* Get server response */ + data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); + printf("Received: %s\n\n", buffer_rec.data); + } + + /* Close UDP communication */ + close(fd); +} diff --git a/test/select/test04_srv.c b/test/select/test04_srv.c new file mode 100755 index 000000000..b6eec6c5e --- /dev/null +++ b/test/select/test04_srv.c @@ -0,0 +1,135 @@ +/* + * Test name: test04_srv.c + * + * Objective: Test a simple UDP server + * + * Description: Implements a simple echo server using the UDP protocol. Instead + * of blocking on read(), it performs a select call first blocking there + * until there is data to be read + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6000L + +/* type for received data */ +typedef struct +{ + udp_io_hdr_t header; + char data[1024]; +} udp_buffer_t; + +int udp_conf(long port) { + + char *udp_device; + int netfd; + nwio_udpopt_t udpopt; + + /* Get default UDP device */ + if ((udp_device = getenv("UDP_DEVICE")) == NULL) + udp_device = UDP_DEVICE; + + /* Open UDP connection */ + if ((netfd = open(udp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening UDP connection\n"); + return -1; + } + + /* Configure UDP connection */ + udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SET | NWUO_EN_LOC | NWUO_DI_BROAD + | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT; + + udpopt.nwuo_locport = (udpport_t) htons(port); + + if ((ioctl(netfd, NWIOSUDPOPT, &udpopt))<0) + { + fprintf(stderr,"Error configuring the connection\n"); + close(netfd); + return -1; + } + + /* Get conf options */ + if ((ioctl(netfd, NWIOGUDPOPT, &udpopt))<0) + { + fprintf(stderr,"Error getting the conf\n"); + close(netfd); + return -1; + } + + return netfd; +} + + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + udp_buffer_t buffer; + ipaddr_t tmp_addr; + udpport_t tmp_port; + int ret; + fd_set fds_read; + + if ((fd = udp_conf(PORT)) < 0) { + fprintf(stderr, "Error configuring UDP connection\n"); + exit(-1); + } + printf("Waiting for messages on port: %ld\n", PORT); + fflush(stdout); + /* Initialize fd_set */ + FD_ZERO(&fds_read); + FD_SET(fd, &fds_read); + + while (1) + { + /* Wait for data available to be read (no timeout) */ + ret = select(4, &fds_read, NULL, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "Error on select: %d", errno); + exit(-1); + } + if (!FD_ISSET(fd, &fds_read)) { + printf("Error: network fd is not ready (?)\n"); + exit(-1); + } + printf("Ready to receive...\n"); + /* Read received data */ + data_read = read(fd, &buffer, sizeof(udp_buffer_t)); + printf("Received data: %s\n", buffer.data); + + /* Can exit if the received string == exit */ + if (!strcmp(buffer.data,"exit")) + break; + + /* Send data back, swap addresses */ + tmp_addr = buffer.header.uih_src_addr; + buffer.header.uih_src_addr = buffer.header.uih_dst_addr; + buffer.header.uih_dst_addr = tmp_addr; + + /* Swap ports */ + tmp_port = buffer.header.uih_src_port; + buffer.header.uih_src_port = buffer.header.uih_dst_port; + buffer.header.uih_dst_port = tmp_port; + + /* Write the same back */ + write(fd, &buffer, data_read); + } + + close(fd); +} diff --git a/test/select/test05_cli.c b/test/select/test05_cli.c new file mode 100644 index 000000000..0c96a38c4 --- /dev/null +++ b/test/select/test05_cli.c @@ -0,0 +1,167 @@ +/* + * Test name: test05_cli.c + * + * Objective: Test a impatient UDP client with timeout and incoming data from + * network and terminal. + * + * Description: Implements a echo client using the UDP protocol. It is + * based on test04_cli, but the difference is that it uses timeout and waits + * for data both from terminal (stdin) and network connection. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6000L + +/* Type for received data */ +typedef struct +{ + udp_io_hdr_t header; + char data[1024]; +} udp_buffer_t; + + +int udp_conf(char *host, long port, udp_io_hdr_t *header) +{ + /* configures UDP connection */ + char *udp_device; + struct hostent *hp; + int netfd; + nwio_udpopt_t udpopt; + ipaddr_t dirhost; + int result; + + /* get host address */ + if ((hp = gethostbyname(host)) == (struct hostent*) NULL) + { + fprintf(stderr,"Unknown host\n"); + return(-1); + } + memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); + + /* Get UDP device */ + if (( udp_device = getenv("UDP_DEVICE") ) == NULL) + udp_device = UDP_DEVICE; + + /* Get UDP connection */ + if ((netfd = open(udp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening UDP device\n"); + return -1; + } + + /* Configure UDP connection */ + udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC | NWUO_DI_BROAD + | NWUO_RP_SET | NWUO_RA_SET | NWUO_RWDATALL | NWUO_DI_IPOPT; + udpopt.nwuo_remaddr = dirhost; + udpopt.nwuo_remport = (udpport_t) htons(port); + + if ((result = ioctl(netfd, NWIOSUDPOPT, &udpopt) ) <0) + { + fprintf(stderr, "Error establishing communication\n"); + printf("Error: %d\n",result); + close(netfd); + return -1; + } + + /* Get configuration for UDP comm */ + if ((result = ioctl(netfd, NWIOGUDPOPT, &udpopt) ) < 0) + { + fprintf(stderr,"Error getting configuration\n"); + printf("Error: %d\n", result); + close(netfd); + return -1; + } + + header->uih_src_addr = udpopt.nwuo_locaddr; + header->uih_dst_addr = udpopt.nwuo_remaddr; + header->uih_src_port = udpopt.nwuo_locport; + header->uih_dst_port = udpopt.nwuo_remport; + + return netfd; +} + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + udp_buffer_t buffer_send, buffer_rec; + fd_set fds_read; + int ret; + struct timeval timeout; + + /* Check parameters */ + if (argc !=2) { + fprintf(stderr,"Usage: %s host\n", argv[0]); + exit(-1); + } + + if ((fd = udp_conf(argv[1], PORT, &buffer_send.header) ) < 0) + exit(-1); + + + while (1) + { + + /* init fd_set */ + FD_ZERO(&fds_read); + FD_SET(0, &fds_read); + FD_SET(fd, &fds_read); + + /* set timeval */ + timeout.tv_sec = 5; + timeout.tv_usec = 0; + printf("Send data: "); + fflush(stdout); + /* Wait until it is possible to write with select */ + ret = select(4, &fds_read, NULL, NULL, &timeout); + if (ret < 0) { + fprintf(stderr, "Error on select waiting for read: %d\n", errno); + exit(-1); + } + if (ret == 0) { + printf("\nClient says: Hey! I want to send data!!\n"); + fflush(stdout); + continue; + } + /* if got message from server */ + if (FD_ISSET(fd, &fds_read)) { + data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); + printf("Server says: %s\n\n", buffer_rec.data); + fflush(stdout); + } + /* if got data from terminal */ + if (FD_ISSET(0, &fds_read)) { + /* Get a string and send it */ + gets(buffer_send.data); + write(fd, &buffer_send, sizeof(udp_buffer_t)); + + /* If data sent is exit then break */ + if (!strcmp(buffer_send.data,"exit")) + break; + /* Get server response */ + data_read = read(fd, &buffer_rec, sizeof(udp_buffer_t)); + printf("Received: %s\n\n", buffer_rec.data); + fflush(stdout); + } + } + + /* Close UDP communication */ + close(fd); +} diff --git a/test/select/test05_srv.c b/test/select/test05_srv.c new file mode 100755 index 000000000..b1d9d80f4 --- /dev/null +++ b/test/select/test05_srv.c @@ -0,0 +1,198 @@ +/* + * Test name: test05_srv.c + * + * Objective: Test an impatient UDP server with timeouts + * + * Description: Implements an echo server using the UDP protocol. It is + * based on test04_srv, but it has a timeout value. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6000L + +/* type for received data */ +typedef struct +{ + udp_io_hdr_t header; + char data[1024]; +} udp_buffer_t; + +int udp_conf(long port) { + + char *udp_device; + int netfd; + nwio_udpopt_t udpopt; + + /* Get default UDP device */ + if ((udp_device = getenv("UDP_DEVICE")) == NULL) + udp_device = UDP_DEVICE; + + /* Open UDP connection */ + if ((netfd = open(udp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening UDP connection\n"); + return -1; + } + + /* Configure UDP connection */ + udpopt.nwuo_flags = NWUO_COPY | NWUO_LP_SET | NWUO_EN_LOC | NWUO_DI_BROAD + | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT; + + udpopt.nwuo_locport = (udpport_t) htons(port); + + if ((ioctl(netfd, NWIOSUDPOPT, &udpopt))<0) + { + fprintf(stderr,"Error configuring the connection\n"); + close(netfd); + return -1; + } + + /* Get conf options */ + if ((ioctl(netfd, NWIOGUDPOPT, &udpopt))<0) + { + fprintf(stderr,"Error getting the conf\n"); + close(netfd); + return -1; + } + + return netfd; +} + + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + udp_buffer_t buffer; + ipaddr_t tmp_addr; + udpport_t tmp_port; + int ret; + fd_set fds_read; + struct timeval timeout; + ipaddr_t client_addr, this_addr; + udpport_t client_port; + + if ((fd = udp_conf(PORT)) < 0) { + fprintf(stderr, "Error configuring UDP connection\n"); + exit(-1); + } + printf("Waiting for messages on port: %ld\n", PORT); + fflush(stdout); + + + /* get a first message so we know who is the client and we can harass it + afterwards */ + + /* Initialize fd_set */ + FD_ZERO(&fds_read); + FD_SET(fd, &fds_read); + /* Set timeout structure */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + ret = select(4, &fds_read, NULL, NULL, NULL); + + if (ret < 0) { + fprintf(stderr, "Error in select\n"); + exit(-1); + } + if (!FD_ISSET(fd, &fds_read)) { + fprintf(stderr, "Error: Should be receiving some data from network(?)\n"); + exit(-1); + } + printf("Ready to receive...\n"); + /* Read received data */ + data_read = read(fd, &buffer, sizeof(udp_buffer_t)); + printf("Received data: %s\n", buffer.data); + + /* Can exit if the received string == exit */ + if (!strcmp(buffer.data,"exit")) + exit(0); + + /* Send data back, swap addresses */ + tmp_addr = buffer.header.uih_src_addr; + buffer.header.uih_src_addr = buffer.header.uih_dst_addr; + buffer.header.uih_dst_addr = tmp_addr; + /* save address of both ends */ + client_addr = tmp_addr; + this_addr = buffer.header.uih_src_addr; + + /* Swap ports */ + tmp_port = buffer.header.uih_src_port; + buffer.header.uih_src_port = buffer.header.uih_dst_port; + buffer.header.uih_dst_port = tmp_port; + /* save client port */ + client_port = tmp_port; + + /* Write the same back */ + write(fd, &buffer, data_read); + + while (1) + { + + /* Initialize fd_set */ + FD_ZERO(&fds_read); + FD_SET(fd, &fds_read); + /* Set timeout structure */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + /* Wait for data available to be read (timeout) */ + ret = select(4, &fds_read, NULL, NULL, &timeout); + if (ret < 0) { + fprintf(stderr, "Error on select: %d", errno); + exit(-1); + } + /* if timeout */ + if (ret == 0) { + /* Send angry msg to client asking for more */ + printf("Tired of waiting, send client an angry message\n"); + buffer.header.uih_src_addr = this_addr; + buffer.header.uih_dst_addr = client_addr; + buffer.header.uih_src_port = PORT; + buffer.header.uih_dst_port = client_port; + strcpy(buffer.data, "Hey! I want to receive some data!\n"); + write(fd, &buffer, sizeof(udp_buffer_t)); + } + /* If receive data from network */ + if (FD_ISSET(fd, &fds_read)) { + printf("Ready to receive...\n"); + /* Read received data */ + data_read = read(fd, &buffer, sizeof(udp_buffer_t)); + printf("Received data: %s\n", buffer.data); + + /* Can exit if the received string == exit */ + if (!strcmp(buffer.data,"exit")) + break; + + /* Send data back, swap addresses */ + tmp_addr = buffer.header.uih_src_addr; + buffer.header.uih_src_addr = buffer.header.uih_dst_addr; + buffer.header.uih_dst_addr = tmp_addr; + + /* Swap ports */ + tmp_port = buffer.header.uih_src_port; + buffer.header.uih_src_port = buffer.header.uih_dst_port; + buffer.header.uih_dst_port = tmp_port; + + /* Write the same back */ + write(fd, &buffer, data_read); + } + } + close(fd); +} diff --git a/test/select/test06_cli.c b/test/select/test06_cli.c new file mode 100755 index 000000000..05f072337 --- /dev/null +++ b/test/select/test06_cli.c @@ -0,0 +1,162 @@ +/* + * Test name: test06_cli.c + * + * Objective: Test a simple TCP client + * + * Description: Implements a simple echo client using the TCP protocol. First + * it waits until it is possible to write (which is always). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6060L + +int tcp_connect(char *host, long port) +{ + /* creates a tcp connection with specified host and port */ + char *tcp_device; + struct hostent *hp; + int netfd; + nwio_tcpcl_t tcpcopt; + nwio_tcpconf_t tcpconf; + ipaddr_t dirhost; + int tries; + int result; + + /* get host address */ + if ((hp = gethostbyname(host)) == (struct hostent*) NULL) + { + fprintf(stderr,"Unknown host\n"); + return(-1); + } + memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); + + /* Get default TCP device */ + if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) + tcp_device = TCP_DEVICE; + + /* Establish TCP connection */ + if ((netfd = open(tcp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening TCP device\n"); + return -1; + } + + /* Configure TCP connection */ + tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; + tcpconf.nwtc_remaddr = dirhost; + tcpconf.nwtc_remport = (tcpport_t) htons(port); + + if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) + { + fprintf(stderr, "Error establishing communication\n"); + printf("Error: %d\n",result); + close(netfd); + return -1; + } + + /* Get configuration for TCP comm */ + if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) + { + fprintf(stderr,"Error getting configuration\n"); + printf("Error: %d\n", result); + close(netfd); + return -1; + } + + /* Establish connection */ + tcpcopt.nwtcl_flags = 0; + tries = 0; + while (tries < 10) { + if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcopt)) < 0 ) { + if (errno != EAGAIN) + { + fprintf(stderr, "Server is not listening\n"); + close(netfd); + return(-1); + } + fprintf(stderr, "Unable to connect\n"); + sleep(1); + tries++; + } + else + break; /* Connection */ + } + /* Check result value */ + if (result < 0) { + fprintf(stderr, "Error connecting\n"); + fprintf(stderr, "Error: %d\n", result); + printf("Number of tries: %d\n", tries); + printf("Error: %d\n", errno); + close(netfd); + return -1; + } + return netfd; +} + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + char send_buf[1024]; + char recv_buf[1024]; + fd_set fds_write; + int ret; + + /* Check parameters */ + if (argc !=2) { + fprintf(stderr,"Usage: %s host\n", argv[0]); + exit(-1); + } + + if ((fd = tcp_connect(argv[1], PORT) ) < 0) + exit(-1); + printf("Connected to server\n"); + /* init fd_set */ + FD_ZERO(&fds_write); + FD_SET(fd, &fds_write); + while (1) + { + /* Wait until it is possible to write with select */ + ret = select(4, NULL, &fds_write, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "Error on select waiting for write: %d\n", errno); + exit(-1); + } + if (!FD_ISSET(fd, &fds_write)) { + fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); + exit(-1); + } + + /* Get a string and send it */ + printf("Ready to write...\n"); + printf("Send data: "); + gets(send_buf); + write(fd, &send_buf, strlen(send_buf)+1); + + /* If data sent is exit then break */ + if (!strcmp(send_buf,"exit")) + break; + + /* Get server response */ + data_read = read(fd, &recv_buf, 1024); + printf("Received: %s\n\n", recv_buf); + } + + /* Close TCP communication */ + close(fd); +} diff --git a/test/select/test06_srv.c b/test/select/test06_srv.c new file mode 100755 index 000000000..99ae283ca --- /dev/null +++ b/test/select/test06_srv.c @@ -0,0 +1,128 @@ +/* + * Test name: test06_srv.c + * + * Objective: Test a simple TCP server + * + * Description: Implements a simple echo server using the TCP protocol. Instead + * of blocking on read(), it performs a select call first blocking there + * until there is data to be read + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6060L + +int listen(long port) { + + char *tcp_device; + int netfd; + nwio_tcpconf_t tcpconf; + nwio_tcpcl_t tcplistenopt; + + /* Get default UDP device */ + if ((tcp_device = getenv("TCP_DEVICE")) == NULL) + tcp_device = TCP_DEVICE; + + /* Open TCP connection */ + if ((netfd = open(tcp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening TCP connection\n"); + return -1; + } + + /* Configure TCP connection */ + tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; + tcpconf.nwtc_locport = (tcpport_t) htons(port); + + if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) + { + fprintf(stderr,"Error configuring the connection\n"); + close(netfd); + return -1; + } + + /* Get communication options */ + if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { + fprintf(stderr, "Error getting configuration\n"); + close(netfd); + return -1; + } + + /* Set conf options */ + tcplistenopt.nwtcl_flags = 0; + printf("Waiting for connections...\n"); + while ((ioctl(netfd, NWIOTCPLISTEN, &tcplistenopt)) == -1) + { + if (errno != EAGAIN) + { + fprintf(stderr,"Unable to listen for connections\n"); + close(netfd); + } + sleep(-1); + } + return netfd; +} + + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + char buffer[1024]; + int ret; + fd_set fds_read; + + if ((fd = listen(PORT)) < 0) { + exit(-1); + } + printf("Waiting for messages on port: %ld\n", PORT); + fflush(stdout); + /* Initialize fd_set */ + FD_ZERO(&fds_read); + FD_SET(fd, &fds_read); + + while (1) + { + /* Wait for data available to be read (no timeout) */ + + ret = select(4, &fds_read, NULL, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "Error on select: %d\n", errno); + exit(-1); + } + if (!FD_ISSET(fd, &fds_read)) { + printf("Error: network fd is not ready (?)\n"); + exit(-1); + } + + printf("Ready to receive...\n"); + /* Read received data */ + data_read = read(fd, &buffer, 1024); + printf("Received data: %s\n", buffer); + + /* Can exit if the received string == exit */ + if (!strcmp(buffer,"exit")) + break; + + /* Write the same back */ + write(fd, &buffer, data_read); + } + printf("Connection finished\n"); + close(fd); +} diff --git a/test/select/test07_cli.c b/test/select/test07_cli.c new file mode 100755 index 000000000..8bc21010a --- /dev/null +++ b/test/select/test07_cli.c @@ -0,0 +1,182 @@ +/* + * Test name: test07_cli.c + * + * Objective: Test an impatient TCP client with timeout which waits input both + * from the terminal and from the network connection. + * + * Description: Implements a echo client using the TCP protocol with a timeout + * value. It waites for data on both the terminal and the network connection and + * prints an angry message asking for more data if there is a timeout. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6060L + +int tcp_connect(char *host, long port) +{ + /* creates a tcp connection with specified host and port */ + char *tcp_device; + struct hostent *hp; + int netfd; + nwio_tcpcl_t tcpcopt; + nwio_tcpconf_t tcpconf; + ipaddr_t dirhost; + int tries; + int result; + + /* get host address */ + if ((hp = gethostbyname(host)) == (struct hostent*) NULL) + { + fprintf(stderr,"Unknown host\n"); + return(-1); + } + memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); + + /* Get default TCP device */ + if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) + tcp_device = TCP_DEVICE; + + /* Establish TCP connection */ + if ((netfd = open(tcp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening TCP device\n"); + return -1; + } + + /* Configure TCP connection */ + tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; + tcpconf.nwtc_remaddr = dirhost; + tcpconf.nwtc_remport = (tcpport_t) htons(port); + + if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) + { + fprintf(stderr, "Error establishing communication\n"); + printf("Error: %d\n",result); + close(netfd); + return -1; + } + + /* Get configuration for TCP comm */ + if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) + { + fprintf(stderr,"Error getting configuration\n"); + printf("Error: %d\n", result); + close(netfd); + return -1; + } + + /* Establish connection */ + tcpcopt.nwtcl_flags = 0; + tries = 0; + while (tries < 10) { + if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcopt)) < 0 ) { + if (errno != EAGAIN) + { + fprintf(stderr, "Server is not listening\n"); + close(netfd); + return(-1); + } + fprintf(stderr, "Unable to connect\n"); + sleep(1); + tries++; + } + else + break; /* Connection */ + } + /* Check result value */ + if (result < 0) { + fprintf(stderr, "Error connecting\n"); + fprintf(stderr, "Error: %d\n", result); + printf("Number of tries: %d\n", tries); + printf("Error: %d\n", errno); + close(netfd); + return -1; + } + return netfd; +} + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + char send_buf[1024]; + char recv_buf[1024]; + fd_set fds_read; + int ret; + struct timeval timeout; + + /* Check parameters */ + if (argc !=2) { + fprintf(stderr,"Usage: %s host\n", argv[0]); + exit(-1); + } + + if ((fd = tcp_connect(argv[1], PORT) ) < 0) + exit(-1); + printf("Connected to server\n"); + + while (1) + { + + /* init fd_set */ + FD_ZERO(&fds_read); + FD_SET(0, &fds_read); /* stdin */ + FD_SET(fd, &fds_read); + /* set timeout */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + + printf("Send data: "); + fflush(stdout); + /* Wait until it is possible to read with select */ + ret = select(4, &fds_read, NULL, NULL, &timeout); + if (ret < 0) { + fprintf(stderr, "Error on select waiting for write: %d\n", errno); + exit(-1); + } + /* timeout */ + if (ret == 0) { + printf("\nClient says: Hey! I want to send some data!!\n"); + continue; + } + /* handle data from network */ + if (FD_ISSET(fd, &fds_read)) { + data_read = read(fd, &recv_buf, 1024); + printf("Server says: %s\n\n", recv_buf); + } + /* handle data from terminal */ + if (FD_ISSET(0, &fds_read)) { + /* Get a string and send it */ + gets(send_buf); + write(fd, &send_buf, strlen(send_buf)+1); + + /* If data sent is exit then break */ + if (!strcmp(send_buf,"exit")) + break; + + /* Get server response */ + data_read = read(fd, &recv_buf, 1024); + printf("Received: %s\n\n", recv_buf); + } + } + + /* Close TCP communication */ + close(fd); +} diff --git a/test/select/test07_srv.c b/test/select/test07_srv.c new file mode 100755 index 000000000..46c4c2e94 --- /dev/null +++ b/test/select/test07_srv.c @@ -0,0 +1,138 @@ +/* + * Test name: test07_srv.c + * + * Objective: Test an impatient TCP server with a timeout. + * + * Description: Implements an echo server using the TCP protocol. It is + * based on test06_srv.c but has a timeout for receiving data from a client + * and if the time is up it sends an angry message to the client requesting + * for more information. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6060L + +int listen(long port) { + + char *tcp_device; + int netfd; + nwio_tcpconf_t tcpconf; + nwio_tcpcl_t tcplistenopt; + + /* Get default UDP device */ + if ((tcp_device = getenv("TCP_DEVICE")) == NULL) + tcp_device = TCP_DEVICE; + + /* Open TCP connection */ + if ((netfd = open(tcp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening TCP connection\n"); + return -1; + } + + /* Configure TCP connection */ + tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; + tcpconf.nwtc_locport = (tcpport_t) htons(port); + + if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) + { + fprintf(stderr,"Error configuring the connection\n"); + close(netfd); + return -1; + } + + /* Get communication options */ + if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { + fprintf(stderr, "Error getting configuration\n"); + close(netfd); + return -1; + } + + /* Set conf options */ + tcplistenopt.nwtcl_flags = 0; + printf("Waiting for connections...\n"); + while ((ioctl(netfd, NWIOTCPLISTEN, &tcplistenopt)) == -1) + { + if (errno != EAGAIN) + { + fprintf(stderr,"Unable to listen for connections\n"); + close(netfd); + } + sleep(-1); + } + return netfd; +} + + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + char buffer[1024]; + int ret; + fd_set fds_read; + struct timeval timeout; + + if ((fd = listen(PORT)) < 0) { + exit(-1); + } + printf("Waiting for messages on port: %ld\n", PORT); + fflush(stdout); + while (1) + { + + /* Initialize fd_set */ + FD_ZERO(&fds_read); + FD_SET(fd, &fds_read); + /* set timeout */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + /* Wait for data available to be read (no timeout) */ + ret = select(4, &fds_read, NULL, NULL, &timeout); + if (ret < 0) { + fprintf(stderr, "Error on select: %d\n", errno); + exit(-1); + } + /* timeout */ + if (ret == 0) { + strcpy(buffer, "I want to get some data!!\n"); + write(fd, &buffer, 1024); + continue; + } + + /* data received from client */ + if (FD_ISSET(fd, &fds_read)) { + printf("Ready to receive...\n"); + /* Read received data */ + data_read = read(fd, &buffer, 1024); + printf("Received data: %s\n", buffer); + + /* Can exit if the received string == exit */ + if (!strcmp(buffer,"exit")) + break; + + /* Write the same back */ + write(fd, &buffer, data_read); + } + } + printf("Connection finished\n"); + close(fd); +} diff --git a/test/select/test08_cli.c b/test/select/test08_cli.c new file mode 100755 index 000000000..20a8cedf1 --- /dev/null +++ b/test/select/test08_cli.c @@ -0,0 +1,183 @@ +/* + * Test name: test08_cli.c + * + * Objective: Test select on urgent data. TCP client. + * + * Description: It is based on test06_cli but sends urgent data. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6060L + +int tcp_connect(char *host, long port) +{ + /* creates a tcp connection with specified host and port */ + char *tcp_device; + struct hostent *hp; + int netfd; + nwio_tcpcl_t tcpcl; + nwio_tcpopt_t tcpopt; + nwio_tcpconf_t tcpconf; + ipaddr_t dirhost; + int tries; + int result; + + /* get host address */ + if ((hp = gethostbyname(host)) == (struct hostent*) NULL) + { + fprintf(stderr,"Unknown host\n"); + return(-1); + } + memcpy((char *)&dirhost, (char *)hp->h_addr, hp->h_length); + + /* Get default TCP device */ + if (( tcp_device = getenv("TCP_DEVICE") ) == NULL) + tcp_device = TCP_DEVICE; + + /* Establish TCP connection */ + if ((netfd = open(tcp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening TCP device\n"); + return -1; + } + + /* Configure TCP connection */ + tcpconf.nwtc_flags=NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; + tcpconf.nwtc_remaddr = dirhost; + tcpconf.nwtc_remport = (tcpport_t) htons(port); + + if ((result = ioctl(netfd, NWIOSTCPCONF, &tcpconf) ) <0) + { + fprintf(stderr, "Error establishing communication\n"); + printf("Error: %d\n",result); + close(netfd); + return -1; + } + + /* Get configuration for TCP comm */ + if ((result = ioctl(netfd, NWIOGTCPCONF, &tcpconf) ) < 0) + { + fprintf(stderr,"Error getting configuration\n"); + printf("Error: %d\n", result); + close(netfd); + return -1; + } + + /* Establish connection options (send URG data) */ + tcpopt.nwto_flags = NWTO_SND_URG_MASK; + + /* Set options for TCP comm */ + if ((result = ioctl(netfd, NWIOSTCPOPT, &tcpopt) ) < 0) + { + fprintf(stderr,"Error getting configuration\n"); + printf("Error: %d\n", result); + close(netfd); + return -1; + } + + /* Get configuration for TCP comm */ + if ((result = ioctl(netfd, NWIOGTCPOPT, &tcpopt) ) < 0) + { + fprintf(stderr,"Error getting options\n"); + printf("Error: %d\n", result); + close(netfd); + return -1; + } + + tcpcl.nwtcl_flags = 0; + tries = 0; + while (tries < 10) { + if ( (result = ioctl(netfd, NWIOTCPCONN, &tcpcl)) < 0 ) { + if (errno != EAGAIN) + { + fprintf(stderr, "Server is not listening\n"); + close(netfd); + return(-1); + } + fprintf(stderr, "Unable to connect\n"); + sleep(1); + tries++; + } + else + break; /* Connection */ + } + /* Check result value */ + if (result < 0) { + fprintf(stderr, "Error connecting\n"); + fprintf(stderr, "Error: %d\n", result); + printf("Number of tries: %d\n", tries); + printf("Error: %d\n", errno); + close(netfd); + return -1; + } + return netfd; +} + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + char send_buf[1024]; + char recv_buf[1024]; + fd_set fds_write; + int ret; + + /* Check parameters */ + if (argc !=2) { + fprintf(stderr,"Usage: %s host\n", argv[0]); + exit(-1); + } + + if ((fd = tcp_connect(argv[1], PORT) ) < 0) + exit(-1); + printf("Connected to server\n"); + /* init fd_set */ + FD_ZERO(&fds_write); + FD_SET(fd, &fds_write); + while (1) + { + /* Wait until it is possible to write with select */ + ret = select(4, NULL, &fds_write, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "Error on select waiting for write: %d\n", errno); + exit(-1); + } + if (!FD_ISSET(fd, &fds_write)) { + fprintf(stderr, "Error: The net connection is not ready for writing (?)\n"); + exit(-1); + } + + /* Get a string and send it */ + printf("Ready to write...\n"); + printf("Send data: "); + gets(send_buf); + write(fd, &send_buf, strlen(send_buf)+1); + + /* If data sent is exit then break */ + if (!strcmp(send_buf,"exit")) + break; + + /* Get server response */ + data_read = read(fd, &recv_buf, 1024); + printf("Received: %s\n\n", recv_buf); + } + + /* Close UDP communication */ + close(fd); +} diff --git a/test/select/test08_srv.c b/test/select/test08_srv.c new file mode 100755 index 000000000..a4eaa793d --- /dev/null +++ b/test/select/test08_srv.c @@ -0,0 +1,146 @@ +/* + * Test name: test08_srv.c + * + * Objective: Test a simple TCP server waiting for urgent data. + * + * Description: Implements a echo TCP server as in test06_srv but waits + * for urgent data, using select on exception. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 6060L + +int listen(long port) { + + char *tcp_device; + int netfd; + nwio_tcpconf_t tcpconf; + nwio_tcpcl_t tcpcl; + nwio_tcpopt_t tcpopt; + + /* Get default UDP device */ + if ((tcp_device = getenv("TCP_DEVICE")) == NULL) + tcp_device = TCP_DEVICE; + + /* Open TCP connection */ + if ((netfd = open(tcp_device, O_RDWR)) < 0) + { + fprintf(stderr,"Error opening TCP connection\n"); + return -1; + } + + /* Configure TCP connection */ + tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; + tcpconf.nwtc_locport = (tcpport_t) htons(port); + + if ((ioctl(netfd, NWIOSTCPCONF, &tcpconf))<0) + { + fprintf(stderr,"Error configuring the connection\n"); + close(netfd); + return -1; + } + + /* Get communication conf*/ + if ((ioctl(netfd, NWIOGTCPCONF, &tcpconf)) < 0) { + fprintf(stderr, "Error getting configuration\n"); + close(netfd); + return -1; + } + + /* Set comm options */ + tcpopt.nwto_flags = NWTO_RCV_URG; + + if ((ioctl(netfd, NWIOSTCPOPT, &tcpopt))<0) + { + fprintf(stderr,"Error configuring the connection\n"); + close(netfd); + return -1; + } + + /* Get communication opt*/ + if ((ioctl(netfd, NWIOGTCPOPT, &tcpopt)) < 0) { + fprintf(stderr, "Error getting options\n"); + close(netfd); + return -1; + } + + /* Set conn options */ + tcpcl.nwtcl_flags = 0; + printf("Waiting for connections...\n"); + while ((ioctl(netfd, NWIOTCPLISTEN, &tcpcl)) == -1) + { + if (errno != EAGAIN) + { + fprintf(stderr,"Unable to listen for connections\n"); + close(netfd); + } + sleep(-1); + } + return netfd; +} + + +int main(int argc,char *argv[]) { + int fd; + ssize_t data_read; + char buffer[1024]; + int ret; + fd_set fds_excep; + + if ((fd = listen(PORT)) < 0) { + exit(-1); + } + printf("Waiting for messages on port: %ld\n", PORT); + fflush(stdout); + /* Initialize fd_set */ + FD_ZERO(&fds_excep); + FD_SET(fd, &fds_excep); + + while (1) + { + /* Wait for data available to be read (no timeout) */ + + ret = select(4, NULL, NULL, &fds_excep, NULL); + if (ret < 0) { + fprintf(stderr, "Error on select: %d\n", errno); + exit(-1); + } + if (!FD_ISSET(fd, &fds_excep)) { + printf("Error: no URG data received (?)\n"); + exit(-1); + } + + printf("Ready to receive...\n"); + /* Read received data */ + data_read = read(fd, &buffer, 1024); + printf("Received data: %s\n", buffer); + + /* Can exit if the received string == exit */ + if (!strcmp(buffer,"exit")) + break; + + /* Write the same back */ + write(fd, &buffer, data_read); + } + printf("Connection finished\n"); + close(fd); +} diff --git a/test/select/test09.c b/test/select/test09.c new file mode 100644 index 000000000..1aa050d4b --- /dev/null +++ b/test/select/test09.c @@ -0,0 +1,63 @@ +/* + * Test name: test09.c + * + * Objetive: The purpose of this test is to make sure that select works + * when working with the terminal. + * + * Description: This tests wait entry from stdin using select and displays + * it again in stdout when it is ready to write (which is always) + * + * Jose M. Gomez + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +void main(void) { + fd_set fds_read, fds_write; + int retval; + char data[1024]; + + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_SET(0, &fds_read); /* stdin */ + FD_SET(1, &fds_write); /* stdout */ + + while(1) { + printf("Input some data: "); + fflush(stdout); + retval=select(3, &fds_read, NULL, NULL, NULL); + if (retval < 0) { + fprintf(stderr, "Error while executing select\n"); + exit(-1); + } + printf("select retval: %d\n", retval); + if (!FD_ISSET(0, &fds_read)) { + fprintf(stderr, "Error: stdin not ready (?)\n"); + exit(-1); + } + printf("gets..\n"); + gets(data); + printf("gets done..\n"); + if (!strcmp(data, "exit")) + exit(0); + printf("Try to write it back\n"); + retval=select(3, NULL, &fds_write, NULL, NULL); + if (retval < 0) { + fprintf(stderr, "Error while executing select\n"); + exit(-1); + } + if (!FD_ISSET(1, &fds_write)) { + fprintf(stderr, "Error: stdout not ready (?)\n"); + exit(-1); + } + printf("Data: %s\n", data); + } +} diff --git a/test/select/test10.c b/test/select/test10.c new file mode 100644 index 000000000..4590520c7 --- /dev/null +++ b/test/select/test10.c @@ -0,0 +1,70 @@ +/* + * Test name: test10.c + * + * Objetive: The purpose of this test is to make sure that select works + * when working with the terminal with timeouts + * + * Description: This tests wait entry from stdin using select and displays + * it again in stdout when it is ready to write (which is always). It has + * a timeout value as well. + * + * Jose M. Gomez + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void main(void) { + fd_set fds_read, fds_write; + int retval; + char data[1024]; + struct timeval timeout; + + while(1) { + timeout.tv_sec = 3; + timeout.tv_usec = 0; + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_SET(0, &fds_read); + FD_SET(1, &fds_write); + printf("Input some data: "); + fflush(stdout); + retval=select(3, &fds_read, NULL, NULL, &timeout); + if (retval < 0) { + fprintf(stderr, "Error while executing select\n"); + exit(-1); + } + if (retval == 0) { + printf("\n Hey! Feed me some data!\n"); + fflush(stdout); + continue; + } + if (!FD_ISSET(0, &fds_read)) { + fprintf(stderr, "Error: stdin not ready (?)\n"); + exit(-1); + } + gets(data); + if (!strcmp(data, "exit")) + exit(0); + printf("Try to write it back\n"); + retval=select(3, NULL, &fds_write, NULL, NULL); + if (retval < 0) { + fprintf(stderr, "Error while executing select\n"); + exit(-1); + } + if (!FD_ISSET(1, &fds_write)) { + fprintf(stderr, "Error: stdout not ready (?)\n"); + exit(-1); + } + printf("Data: %s\n", data); + } +} diff --git a/test/select/test11.c b/test/select/test11.c new file mode 100644 index 000000000..5126f60cd --- /dev/null +++ b/test/select/test11.c @@ -0,0 +1,162 @@ +/* + * Test name: test11.c + * + * Objetive: The purpose of this test is to make sure that select works + * with pipes. + * + * Description: The select checks are divided in checks on writing for the + * parent process, which has the writing end of the pipe, and checks on reading + * and exception on the child process, which has the reading end of pipe. So + * when the first process is ready to write to the pipe it will request a string + * from the terminal and send it through the pipe. If the string is 'exit' then + * the pipe is closed. The child process is blocked in a select checking for read + * and exception. If there is data to be read then it will perform the read and + * prints the read data. If the pipe is closed (user typed 'exit'), the child + * process finishes. + * + * Jose M. Gomez + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void pipehandler(int sig) +{ + +} + +void do_child(int data_pipe[]) +{ + /* reads from pipe and prints out the data */ + char data[2048]; + int retval; + fd_set fds_read; + fd_set fds_exception; + struct timeval timeout; + + signal(SIGPIPE, pipehandler); + signal(SIGUSR1, pipehandler); + + /* first, close the write part of the pipe, since it is not needed */ + close(data_pipe[1]); + + while(1) { + FD_ZERO(&fds_read); + FD_ZERO(&fds_exception); + FD_SET(data_pipe[0], &fds_read); + FD_SET(data_pipe[0], &fds_exception); + timeout.tv_sec = 5; + timeout.tv_usec = 0; + retval = select(data_pipe[0]+1, &fds_read, NULL, &fds_exception, &timeout); + if (retval == -1) { + perror("select"); + fprintf(stderr, "child: Error in select\n"); + continue; + } else printf("child select: %d\n", retval); + if (FD_ISSET(data_pipe[0], &fds_exception)) { + printf("child: exception fd set. quitting.\n"); + break; + } + if (FD_ISSET(data_pipe[0], &fds_read)) { + printf("child: read fd set. reading.\n"); + if ((retval = read(data_pipe[0], data, sizeof(data))) < 0) { + perror("read"); + fprintf(stderr, "child: couldn't read from pipe\n"); + exit(-1); + } + if(retval == 0) { + fprintf(stderr, "child: eof on pipe\n"); + break; + } + data[retval] = '\0'; + printf("pid %d Pipe reads (%d): %s\n", getpid(), retval, data); + } else printf("child: no fd set\n"); + } + + /* probably pipe was broken, or got EOF via the pipe. */ + exit(0); +} + +void do_parent(int data_pipe[]) +{ + char data[1024]; + int retval; + fd_set fds_write; + + signal(SIGPIPE, pipehandler); + signal(SIGUSR1, pipehandler); + + /* first, close the read part of pipe, since it is not needed */ + close(data_pipe[0]); + + /* now enter a loop of read user input, and writing it to the pipe */ + while (1) { + FD_ZERO(&fds_write); + FD_SET(data_pipe[1], &fds_write); + printf("pid %d Waiting for pipe ready to write...\n", getpid()); + retval = select(data_pipe[1]+1, NULL, &fds_write, NULL, NULL); + if (retval == -1) { + perror("select"); + fprintf(stderr, "Parent: Error in select\n"); + exit(-1); + } + + printf("Input data: "); + if(!gets(data)) { + printf("parent: eof; exiting\n"); + break; + } + if (!strcmp(data, "exit")) + break; + if (!FD_ISSET(data_pipe[1], &fds_write)) { + fprintf(stderr, "parent: write fd not set?! retrying\n"); + continue; + } + retval = write(data_pipe[1], &data, 1024); + if (retval == -1) { + perror("write"); + fprintf(stderr, "Error writing on pipe\n"); + exit(-1); + } + } + + /* got exit from user */ + close(data_pipe[1]); /* close pipe, let child know we're done */ + wait(&retval); + printf("Child exited with status: %d\n", retval); + exit(0); +} + +void main(void) { + int pipes[2]; + int retval; + int pid; + + /* create the pipe */ + retval = pipe(pipes); + if (retval == -1) { + perror("pipe"); + fprintf(stderr, "Error creating the pipe\n"); + exit(-1); + } + pid = fork(); + if (pid == -1) { + fprintf(stderr, "Error forking\n"); + exit(-1); + } + + if (pid == 0) /* child proc */ + do_child(pipes); + else + do_parent(pipes); +} diff --git a/test/select/test12.c b/test/select/test12.c new file mode 100644 index 000000000..f69d876da --- /dev/null +++ b/test/select/test12.c @@ -0,0 +1,39 @@ +/* + * Test name: test12.c + * + * Objective: The purpose of this check the behaviour when a signal is received + * and there is a handler. + * + * Description: The program handles SIGHUP and expects the user to actually send + * the signal from other terminal with 'kill -1 pid' + + * Jose M. Gomez + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SECONDS 15 + +void catch_hup(int sig_num) +{ + /* don't need to reset signal handler */ + printf("Received a SIGHUP, inside the handler now\n"); +} + +int main(void) { + int ret; /* return value */ + + /* set the HUP sginal handler to 'catch_hup' */ + signal(SIGHUP, catch_hup); + /* Get proc_id and print it */ + printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); + printf("Blocking now on select...\n", SECONDS); + ret = select(0, NULL, NULL, NULL, NULL); + printf("Errno: %d\n", errno); +} diff --git a/test/select/test13a.c b/test/select/test13a.c new file mode 100644 index 000000000..9b76bd801 --- /dev/null +++ b/test/select/test13a.c @@ -0,0 +1,56 @@ +/* + * Test name: test13a.c + * + * Objective: The purpose of this tests is to show how a select can + * get into a race condition when dealing with signals. + * + * Description: The program waits for SIGHUP or input in the terminal + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int got_sighup = 0; + +void catch_hup(int sig_num) +{ + printf("Received a SIGHUP, set global vble \n"); + got_sighup = 1; +} + +int main(void) { + int ret; /* return value */ + fd_set read_fds; + char data[1024]; + + /* Init read fd_set */ + FD_ZERO(&read_fds); + FD_SET(0, &read_fds); + + /* set the HUP signal handler to 'catch_hup' */ + signal(SIGHUP, catch_hup); + + /* Get proc_id and print it */ + printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); + printf("Going to sleep for 5 seconds, if the signal arrives meanwhile\n"); + printf("the process will be blocked until there is input in the keyboard\n"); + printf("if the signal arrives after the timeout and while in select, it will\n"); + printf("behave as it should.\n"); + printf("Sleeping for 5 secs\n"); + sleep(5); + + printf("Blocking now on select...\n"); + ret = select(1, &read_fds, NULL, NULL, NULL); + if (got_sighup) { + printf("We have a sighup signal so exit the program\n"); + exit(0); + } + gets(data); + printf("Got entry for terminal then, bye\n"); +} diff --git a/test/select/test13b.c b/test/select/test13b.c new file mode 100644 index 000000000..8d14a0523 --- /dev/null +++ b/test/select/test13b.c @@ -0,0 +1,67 @@ +/* + * Test name: test13b.c + * + * Objective: The purpose of this tests is to show how pselect() + * solves the situation shown in test13a.c + * + * Description: The program waits for SIGHUP or input in the terminal + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int got_sighup = 0; + +void catch_hup(int sig_num) +{ + printf("Received a SIGHUP, set global vble \n"); + got_sighup = 1; +} + +int main(void) { + int ret; /* return value */ + fd_set read_fds; + sigset_t sigmask, orig_sigmask; + char data[1024]; + + /* Init read fd_set */ + FD_ZERO(&read_fds); + FD_SET(0, &read_fds); + + /* set the signal masks */ + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGHUP); + sigprocmask( SIG_BLOCK, &sigmask, &orig_sigmask); + + /* set the HUP signal handler to 'catch_hup' */ + signal(SIGHUP, catch_hup); + + /* Get proc_id and print it */ + printf("Send a signal from other terminal with: kill -1 %d\n", getpid()); + printf("Going to sleep for 5 seconds, if the signal arrives meanwhile\n"); + printf("the process will be blocked until there is input in the keyboard\n"); + printf("if the signal arrives after the timeout and while in select, it will\n"); + printf("behave as it should.\n"); + printf("Sleeping for 5 secs\n"); + sleep(5); + + printf("Blocking now on select...\n"); +#if 0 + ret = pselect(1, &read_fds, NULL, NULL, NULL, &orig_sigmask); +#else + ret = -1; +#endif + if (got_sighup) { + printf("We have a sighup signal so exit the program\n"); + exit(0); + } + gets(data); + printf("Got entry for terminal then, bye\n"); + +} -- 2.44.0