Describe kqclient.c program
[eleutheria.git] / kqueue / kqclient.c
blobea52ebfc24015e2b7260cdd288e64db2cf72bddc
1 /* compile with:
2 gcc kqclient.c -o kqclient -Wall -W -Wextra -ansi -pedantic
4 We will implement a raw tcp client using the kqueue framework.
5 Whenever the host sends data to the socket, we will print them
6 in the standard output stream. Similarly, when the user types
7 something in the standard input stream, we will send it to the
8 host through the socket.
9 Basically, we need to monitor the following:
11 1. any incoming host data in the socket
12 2. any user data in the standard input stream
15 #include <netinet/in.h>
16 #include <sys/event.h>
17 #include <sys/socket.h>
18 #include <sys/time.h>
19 #include <netdb.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
25 #define BUFSIZE 1024
27 /* function prototypes */
28 void diep(const char *s);
29 int tcpopen(const char *host, int port);
30 void sendbuftosck(int sckfd, const char *buf, int len);
32 int main(int argc, char *argv[])
34 struct kevent chlist[2]; /* events we want to monitor */
35 struct kevent evlist[2]; /* events that were triggered */
36 char buf[BUFSIZE];
37 int sckfd, kq, nev, i;
39 /* check argument count */
40 if (argc != 3) {
41 fprintf(stderr, "usage: %s host port\n", argv[0]);
42 exit(EXIT_FAILURE);
45 /* open a connection to a host:port pair */
46 sckfd = tcpopen(argv[1], atoi(argv[2]));
48 /* create a new kernel event queue */
49 if ((kq = kqueue()) == -1)
50 diep("kqueue()");
52 /* initialise kevent structures */
53 EV_SET(&chlist[0], sckfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
54 EV_SET(&chlist[1], fileno(stdin), EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
56 /* loop forever */
57 for (;;) {
58 nev = kevent(kq, chlist, 2, evlist, 2, NULL);
60 if (nev < 0)
61 diep("kevent()");
63 else if (nev > 0) {
64 if (evlist[0].flags & EV_EOF) /* read direction of socket has shutdown */
65 exit(EXIT_FAILURE);
67 for (i = 0; i < nev; i++) {
68 if (evlist[i].flags & EV_ERROR) { /* report errors */
69 fprintf(stderr, "EV_ERROR: %s\n", strerror(evlist[i].data));
70 exit(EXIT_FAILURE);
73 if (evlist[i].ident == sckfd) { /* we have data from the host */
74 memset(buf, 0, BUFSIZE);
75 if (read(sckfd, buf, BUFSIZE) < 0)
76 diep("read()");
77 fputs(buf, stdout);
80 else if (evlist[i].ident == fileno(stdin)) { /* we have data from stdin */
81 memset(buf, 0, BUFSIZE);
82 fgets(buf, BUFSIZE, stdin);
83 sendbuftosck(sckfd, buf, strlen(buf));
89 close(kq);
90 return EXIT_SUCCESS;
93 void diep(const char *s)
95 perror(s);
96 exit(EXIT_FAILURE);
99 int tcpopen(const char *host, int port)
101 struct sockaddr_in server;
102 struct hostent *hp;
103 int sckfd;
105 if ((hp = gethostbyname(host)) == NULL)
106 diep("gethostbyname()");
108 if ((sckfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
109 diep("socket()");
111 server.sin_family = AF_INET;
112 server.sin_port = htons(port);
113 server.sin_addr = *((struct in_addr *)hp->h_addr);
114 memset(&(server.sin_zero), 0, 8);
116 if (connect(sckfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) < 0)
117 diep("connect()");
119 return sckfd;
122 void sendbuftosck(int sckfd, const char *buf, int len)
124 int bytessent, pos;
126 pos = 0;
127 do {
128 if ((bytessent = send(sckfd, buf + pos, len - pos, 0)) < 0)
129 diep("send()");
130 pos += bytessent;
131 } while (bytessent > 0);