Select test-set imported from the minix contributions, with permission
to modify and distribute from Jose Manuel Gomez, the author (jmgomez@linuxmail.org).
This commit is contained in:
parent
f81ac6ae5c
commit
ed2a024d47
22 changed files with 2509 additions and 0 deletions
38
test/select/Makefile
Normal file
38
test/select/Makefile
Normal file
|
@ -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
|
60
test/select/speed.c
Normal file
60
test/select/speed.c
Normal file
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
46
test/select/test00.c
Normal file
46
test/select/test00.c
Normal file
|
@ -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;
|
||||||
|
}
|
72
test/select/test01.c
Normal file
72
test/select/test01.c
Normal file
|
@ -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;
|
||||||
|
}
|
112
test/select/test02.c
Normal file
112
test/select/test02.c
Normal file
|
@ -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");
|
||||||
|
}
|
136
test/select/test03.c
Normal file
136
test/select/test03.c
Normal file
|
@ -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");
|
||||||
|
}
|
149
test/select/test04_cli.c
Executable file
149
test/select/test04_cli.c
Executable file
|
@ -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);
|
||||||
|
}
|
135
test/select/test04_srv.c
Executable file
135
test/select/test04_srv.c
Executable file
|
@ -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);
|
||||||
|
}
|
167
test/select/test05_cli.c
Normal file
167
test/select/test05_cli.c
Normal file
|
@ -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);
|
||||||
|
}
|
198
test/select/test05_srv.c
Executable file
198
test/select/test05_srv.c
Executable file
|
@ -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);
|
||||||
|
}
|
162
test/select/test06_cli.c
Executable file
162
test/select/test06_cli.c
Executable file
|
@ -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);
|
||||||
|
}
|
128
test/select/test06_srv.c
Executable file
128
test/select/test06_srv.c
Executable file
|
@ -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);
|
||||||
|
}
|
182
test/select/test07_cli.c
Executable file
182
test/select/test07_cli.c
Executable file
|
@ -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);
|
||||||
|
}
|
138
test/select/test07_srv.c
Executable file
138
test/select/test07_srv.c
Executable file
|
@ -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);
|
||||||
|
}
|
183
test/select/test08_cli.c
Executable file
183
test/select/test08_cli.c
Executable file
|
@ -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);
|
||||||
|
}
|
146
test/select/test08_srv.c
Executable file
146
test/select/test08_srv.c
Executable file
|
@ -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);
|
||||||
|
}
|
63
test/select/test09.c
Normal file
63
test/select/test09.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
70
test/select/test10.c
Normal file
70
test/select/test10.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
162
test/select/test11.c
Normal file
162
test/select/test11.c
Normal file
|
@ -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);
|
||||||
|
}
|
39
test/select/test12.c
Normal file
39
test/select/test12.c
Normal file
|
@ -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);
|
||||||
|
}
|
56
test/select/test13a.c
Normal file
56
test/select/test13a.c
Normal file
|
@ -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");
|
||||||
|
}
|
67
test/select/test13b.c
Normal file
67
test/select/test13b.c
Normal file
|
@ -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");
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue