]> Zhao Yanbai Git Server - minix.git/commitdiff
Select test-set imported from the minix contributions, with permission
authorBen Gras <ben@minix3.org>
Fri, 17 Jun 2005 13:45:40 +0000 (13:45 +0000)
committerBen Gras <ben@minix3.org>
Fri, 17 Jun 2005 13:45:40 +0000 (13:45 +0000)
to modify and distribute from Jose Manuel Gomez, the author
(jmgomez@linuxmail.org).

22 files changed:
test/select/Makefile [new file with mode: 0644]
test/select/speed.c [new file with mode: 0644]
test/select/test00.c [new file with mode: 0644]
test/select/test01.c [new file with mode: 0644]
test/select/test02.c [new file with mode: 0644]
test/select/test03.c [new file with mode: 0644]
test/select/test04_cli.c [new file with mode: 0755]
test/select/test04_srv.c [new file with mode: 0755]
test/select/test05_cli.c [new file with mode: 0644]
test/select/test05_srv.c [new file with mode: 0755]
test/select/test06_cli.c [new file with mode: 0755]
test/select/test06_srv.c [new file with mode: 0755]
test/select/test07_cli.c [new file with mode: 0755]
test/select/test07_srv.c [new file with mode: 0755]
test/select/test08_cli.c [new file with mode: 0755]
test/select/test08_srv.c [new file with mode: 0755]
test/select/test09.c [new file with mode: 0644]
test/select/test10.c [new file with mode: 0644]
test/select/test11.c [new file with mode: 0644]
test/select/test12.c [new file with mode: 0644]
test/select/test13a.c [new file with mode: 0644]
test/select/test13b.c [new file with mode: 0644]

diff --git a/test/select/Makefile b/test/select/Makefile
new file mode 100644 (file)
index 0000000..1803aac
--- /dev/null
@@ -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 (file)
index 0000000..cf0d36a
--- /dev/null
@@ -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 <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/asynchio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <net/netlib.h>
+#include <time.h>
+
+
+#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 (file)
index 0000000..c49fb89
--- /dev/null
@@ -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 <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+int main(int argc, char *argv[]) {
+       fd_set fds;
+       int i,j;        
+
+       FD_ZERO(&fds);
+       for (i=0;i<FD_SETSIZE;i++) {
+               FD_SET(i, &fds);
+               for(j = 0; j <= i; j++)
+                       if(!FD_ISSET(j, &fds))
+                               return 1;
+               for(; j < FD_SETSIZE; j++) 
+                       if(FD_ISSET(j, &fds))
+                               return 1;
+       }
+       for (i=0;i<FD_SETSIZE;i++) {
+               FD_CLR(i, &fds);
+               for(j = 0; j <= i; j++)
+                       if(FD_ISSET(j, &fds))
+                               return 1;
+               for(; j < FD_SETSIZE; j++) 
+                       if(!FD_ISSET(j, &fds))
+                               return 1;
+       }
+       printf("ok\n");
+       return 0;
+}
diff --git a/test/select/test01.c b/test/select/test01.c
new file mode 100644 (file)
index 0000000..16f636a
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Test name: test01.c
+ *
+ * Objective: The purpose of this test is to make sure that the timeout mechanisms
+ * work without errors.
+ * 
+ * Description: Executes a select as if it was a sleep and compares the time it
+ * has been actually sleeping against the specified time in the select call.
+ * Three cases are tested: first, a timeout specified in seconds, second, a timeout in 
+ * microseconds, and third, a timeout with more precision than seconds.
+ *
+ * Jose M. Gomez
+ */
+
+#include <sys/types.h>
+#include <sys/select.h>
+#include <time.h>
+#include <stdio.h>
+#include <errno.h>
+
+#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 (file)
index 0000000..93a2b23
--- /dev/null
@@ -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 <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+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 (file)
index 0000000..98838ad
--- /dev/null
@@ -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 <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+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 (executable)
index 0000000..8bf41fc
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/udp.h>
+#include <net/gen/udp_hdr.h>
+#include <net/gen/udp_io.h>
+#include <net/hton.h>
+
+#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 (executable)
index 0000000..b6eec6c
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/udp.h>
+#include <net/gen/udp_hdr.h>
+#include <net/gen/udp_io.h>
+#include <net/hton.h>
+
+#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 (file)
index 0000000..0c96a38
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/asynchio.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/udp.h>
+#include <net/gen/udp_hdr.h>
+#include <net/gen/udp_io.h>
+#include <net/hton.h>
+
+#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 (executable)
index 0000000..b1d9d80
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/asynchio.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/udp.h>
+#include <net/gen/udp_hdr.h>
+#include <net/gen/udp_io.h>
+#include <net/hton.h>
+
+#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 (executable)
index 0000000..05f0723
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/hton.h>
+
+#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 (executable)
index 0000000..99ae283
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/hton.h>
+#include <net/gen/inet.h>
+
+#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 (executable)
index 0000000..8bc2101
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/asynchio.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/hton.h>
+
+#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 (executable)
index 0000000..46c4c2e
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <sys/asynchio.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/hton.h>
+#include <net/gen/inet.h>
+
+#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 (executable)
index 0000000..20a8ced
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/hton.h>
+
+#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 (executable)
index 0000000..a4eaa79
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/hton.h>
+#include <net/gen/inet.h>
+
+#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 (file)
index 0000000..1aa050d
--- /dev/null
@@ -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 <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+
+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 (file)
index 0000000..4590520
--- /dev/null
@@ -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 <time.h>
+#include <sys/types.h>
+#include <sys/asynchio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+
+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 (file)
index 0000000..5126f60
--- /dev/null
@@ -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 <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/asynchio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <signal.h>
+
+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 (file)
index 0000000..f69d876
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/select.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+
+#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 (file)
index 0000000..9b76bd8
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/select.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+
+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 (file)
index 0000000..8d14a05
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/select.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+
+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");
+       
+}