Commit faa3a30be0bce7fd679b8c07692381b1f8a3b58d

Authored by Grzegorz Jabłoński
1 parent ce434124

Fixed epoll example

Showing 1 changed file with 193 additions and 171 deletions
epoll4.c
1   -/*
  1 +/*
2 2 * Attention:
3   - * To keep things simple, do not handle socket/bind/listen/.../epoll_create/epoll_wait API error
  3 + * To keep things simple, do not handle
  4 + * socket/bind/listen/.../epoll_create/epoll_wait API error
4 5 */
5   -#include <sys/types.h>
6   -#include <sys/socket.h>
7   -#include <netdb.h>
8   -#include <string.h>
9   -#include <unistd.h>
10   -#include <fcntl.h>
11   -#include <sys/epoll.h>
  6 +#include <arpa/inet.h>
12 7 #include <errno.h>
  8 +#include <fcntl.h>
  9 +#include <netdb.h>
13 10 #include <stdio.h>
14 11 #include <stdlib.h>
15   -#include <arpa/inet.h>
16   -
  12 +#include <string.h>
  13 +#include <sys/epoll.h>
  14 +#include <sys/socket.h>
  15 +#include <sys/types.h>
  16 +#include <unistd.h>
17 17  
18   -#define DEFAULT_PORT 9734
19   -#define MAX_CONN 16
20   -#define MAX_EVENTS 32
21   -#define BUF_SIZE 16
22   -#define MAX_LINE 256
  18 +#define DEFAULT_PORT 9734
  19 +#define MAX_CONN 16
  20 +#define MAX_EVENTS 32
  21 +#define BUF_SIZE 16
  22 +#define MAX_LINE 256
23 23  
24 24 void server_run();
25 25 void client_run();
26 26  
27   -int main(int argc, char *argv[])
28   -{
29   - int opt;
30   - char role = 's';
31   - while ((opt = getopt(argc, argv, "cs")) != -1) {
32   - switch (opt) {
33   - case 'c':
34   - role = 'c';
35   - break;
36   - case 's':
37   - break;
38   - default:
39   - printf("usage: %s [-cs]\n", argv[0]);
40   - exit(1);
41   - }
42   - }
43   - if (role == 's') {
44   - server_run();
45   - } else {
46   - client_run();
47   - }
48   - return 0;
  27 +int main(int argc, char *argv[]) {
  28 + int opt;
  29 + char role = 's';
  30 + while ((opt = getopt(argc, argv, "cs")) != -1) {
  31 + switch (opt) {
  32 + case 'c':
  33 + role = 'c';
  34 + break;
  35 + case 's':
  36 + break;
  37 + default:
  38 + printf("usage: %s [-cs]\n", argv[0]);
  39 + exit(1);
  40 + }
  41 + }
  42 + if (role == 's') {
  43 + server_run();
  44 + } else {
  45 + client_run();
  46 + }
  47 + return 0;
49 48 }
50 49  
51 50 /*
52 51 * register events of fd to epfd
53 52 */
54   -static void epoll_ctl_add(int epfd, int fd, uint32_t events)
55   -{
56   - struct epoll_event ev;
57   - ev.events = events;
58   - ev.data.fd = fd;
59   - if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
60   - perror("epoll_ctl()\n");
61   - exit(1);
62   - }
  53 +static void epoll_ctl_add(int epfd, int fd, uint32_t events) {
  54 + struct epoll_event ev;
  55 + ev.events = events;
  56 + ev.data.fd = fd;
  57 + if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
  58 + perror("epoll_ctl()\n");
  59 + exit(1);
  60 + }
63 61 }
64 62  
65   -static void set_sockaddr(struct sockaddr_in *addr)
66   -{
67   - bzero((char *)addr, sizeof(struct sockaddr_in));
68   - addr->sin_family = AF_INET;
69   - addr->sin_addr.s_addr = INADDR_ANY;
70   - addr->sin_port = htons(DEFAULT_PORT);
  63 +static void set_sockaddr(struct sockaddr_in *addr) {
  64 + bzero((char *)addr, sizeof(struct sockaddr_in));
  65 + addr->sin_family = AF_INET;
  66 + addr->sin_addr.s_addr = INADDR_ANY;
  67 + addr->sin_port = htons(DEFAULT_PORT);
71 68 }
72 69  
73   -static int setnonblocking(int sockfd)
74   -{
75   - if (fcntl(sockfd, F_SETFD, fcntl(sockfd, F_GETFD, 0) | O_NONBLOCK) ==
76   - -1) {
77   - return -1;
78   - }
79   - return 0;
  70 +static int setnonblocking(int sockfd) {
  71 + if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK) == -1) {
  72 + perror("fcntl set nonblock");
  73 + return -1;
  74 + }
  75 + return 0;
80 76 }
81 77  
82 78 /*
83 79 * epoll echo server
84 80 */
85   -void server_run()
86   -{
87   - int i;
88   - int n;
89   - int epfd;
90   - int nfds;
91   - int listen_sock;
92   - int conn_sock;
93   - int socklen;
94   - char buf[BUF_SIZE];
95   - struct sockaddr_in srv_addr;
96   - struct sockaddr_in cli_addr;
97   - struct epoll_event events[MAX_EVENTS];
98   -
99   - listen_sock = socket(AF_INET, SOCK_STREAM, 0);
100   -
101   - set_sockaddr(&srv_addr);
102   - bind(listen_sock, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
103   -
104   - setnonblocking(listen_sock);
105   - listen(listen_sock, MAX_CONN);
106   -
107   - epfd = epoll_create(1);
108   - epoll_ctl_add(epfd, listen_sock, EPOLLIN | EPOLLOUT | EPOLLET);
109   -
110   - socklen = sizeof(cli_addr);
111   - for (;;) {
112   - nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
113   - for (i = 0; i < nfds; i++) {
114   - if (events[i].data.fd == listen_sock) {
115   - /* handle new connection */
116   - conn_sock =
117   - accept(listen_sock,
118   - (struct sockaddr *)&cli_addr,
119   - &socklen);
120   -
121   - inet_ntop(AF_INET, (char *)&(cli_addr.sin_addr),
122   - buf, sizeof(cli_addr));
123   - printf("[+] connected with %s:%d\n", buf,
124   - ntohs(cli_addr.sin_port));
125   -
126   - setnonblocking(conn_sock);
127   - epoll_ctl_add(epfd, conn_sock,
128   - EPOLLIN | EPOLLET | EPOLLRDHUP |
129   - EPOLLHUP);
130   - } else if (events[i].events & EPOLLIN) {
131   - /* handle EPOLLIN event */
132   - for (;;) {
133   - bzero(buf, sizeof(buf));
134   - n = read(events[i].data.fd, buf,
135   - sizeof(buf) - 1);
136   - if (n <= 0 /* || errno == EAGAIN */ ) {
137   - break;
138   - } else {
139   - printf("[+] data: %s\n", buf);
140   - write(events[i].data.fd, buf,
141   - strlen(buf));
142   - }
143   - }
144   - } else {
145   - printf("[+] unexpected\n");
146   - }
147   - /* check if the connection is closing */
148   - if (events[i].events & (EPOLLRDHUP | EPOLLHUP)) {
149   - printf("[+] connection closed\n");
150   - epoll_ctl(epfd, EPOLL_CTL_DEL,
151   - events[i].data.fd, NULL);
152   - close(events[i].data.fd);
153   - continue;
154   - }
155   - }
156   - }
  81 +void server_run() {
  82 + int i;
  83 + int n;
  84 + int epfd;
  85 + int nfds;
  86 + int listen_sock;
  87 + int conn_sock;
  88 + socklen_t socklen;
  89 + char buf[BUF_SIZE];
  90 + struct sockaddr_in srv_addr;
  91 + struct sockaddr_in cli_addr;
  92 + struct epoll_event events[MAX_EVENTS];
  93 +
  94 + listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  95 +
  96 + set_sockaddr(&srv_addr);
  97 +
  98 + int reuseaddr = 1;
  99 + if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
  100 + sizeof(int)) < 0)
  101 + perror("setsockopt(SO_REUSEADDR)");
  102 +
  103 + if (bind(listen_sock, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) < 0) {
  104 + perror("bind");
  105 + exit(1);
  106 + }
  107 +
  108 + setnonblocking(listen_sock);
  109 + if (listen(listen_sock, MAX_CONN) < 0) {
  110 + perror("listen");
  111 + exit(1);
  112 + }
  113 +
  114 + epfd = epoll_create(1);
  115 + epoll_ctl_add(epfd, listen_sock, EPOLLIN | EPOLLOUT);
  116 +
  117 + socklen = sizeof(cli_addr);
  118 + for (;;) {
  119 + nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
  120 + for (i = 0; i < nfds; i++) {
  121 + if (events[i].data.fd == listen_sock) {
  122 + /* handle new connection */
  123 + conn_sock = accept(listen_sock, (struct sockaddr *)&cli_addr, &socklen);
  124 +
  125 + inet_ntop(AF_INET, (char *)&(cli_addr.sin_addr), buf, sizeof(buf));
  126 + printf("[+] connected with %s:%d\n", buf, ntohs(cli_addr.sin_port));
  127 +
  128 + setnonblocking(conn_sock);
  129 + epoll_ctl_add(epfd, conn_sock,
  130 + EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP);
  131 + } else if (events[i].events & EPOLLIN) {
  132 + /* handle EPOLLIN event */
  133 + for (;;) {
  134 + bzero(buf, sizeof(buf));
  135 + errno = 0;
  136 + n = read(events[i].data.fd, buf, sizeof(buf) - 1);
  137 + if (n == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
  138 + break;
  139 + } else if (n == 0) {
  140 + break;
  141 + } else {
  142 + printf("[+] data: %s\n", buf);
  143 + n = 0;
  144 + while (n != strlen(buf)) {
  145 + int rv = write(events[i].data.fd, buf + n, strlen(buf) - n);
  146 + if (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
  147 + continue; // FIXME: busy waiting - should wait using epoll
  148 + if (rv == -1)
  149 + break;
  150 + n += rv;
  151 + }
  152 + }
  153 + }
  154 + } else {
  155 + printf("[+] unexpected\n");
  156 + }
  157 + /* check if the connection is closing */
  158 + if (events[i].events & (EPOLLRDHUP | EPOLLHUP)) {
  159 + printf("[+] connection closed\n");
  160 + epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
  161 + close(events[i].data.fd);
  162 + continue;
  163 + }
  164 + }
  165 + }
157 166 }
158 167  
159 168 /*
160   - * test clinet
  169 + * test clinet
161 170 */
162   -void client_run()
163   -{
164   - int n;
165   - int c;
166   - int sockfd;
167   - char buf[MAX_LINE];
168   - struct sockaddr_in srv_addr;
169   -
170   - sockfd = socket(AF_INET, SOCK_STREAM, 0);
171   -
172   - set_sockaddr(&srv_addr);
173   -
174   - if (connect(sockfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) < 0) {
175   - perror("connect()");
176   - exit(1);
177   - }
178   -
179   - for (;;) {
180   - printf("input: ");
181   - fgets(buf, sizeof(buf), stdin);
182   - c = strlen(buf) - 1;
183   - buf[c] = '\0';
184   - write(sockfd, buf, c + 1);
185   -
186   - bzero(buf, sizeof(buf));
187   - while (errno != EAGAIN
188   - && (n = read(sockfd, buf, sizeof(buf) - 1)) > 0) {
189   - printf("echo: %s\n", buf);
190   - bzero(buf, sizeof(buf));
191   -
192   - c -= n;
193   - if (c <= 0) {
194   - break;
195   - }
196   - }
197   - }
198   - close(sockfd);
  171 +void client_run() {
  172 + int n;
  173 + int c;
  174 + int sockfd;
  175 + char buf[MAX_LINE];
  176 + struct sockaddr_in srv_addr;
  177 +
  178 + sockfd = socket(AF_INET, SOCK_STREAM, 0);
  179 +
  180 + set_sockaddr(&srv_addr);
  181 +
  182 + if (connect(sockfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) < 0) {
  183 + perror("connect()");
  184 + exit(1);
  185 + }
  186 +
  187 + for (;;) {
  188 + printf("input: ");
  189 + fgets(buf, sizeof(buf), stdin);
  190 + c = strlen(buf);
  191 +
  192 + n = 0;
  193 + while (n != c) {
  194 + errno = 0;
  195 + int rv = write(sockfd, buf + n, c - n);
  196 + if (rv == -1 && (errno == EINTR))
  197 + continue;
  198 + if (rv == -1)
  199 + exit(1);
  200 + n += rv;
  201 + }
  202 +
  203 + errno = 0;
  204 +
  205 + n = 0;
  206 + while (n != c) {
  207 + errno = 0;
  208 + int rv = read(sockfd, buf + n, c - n);
  209 + if (rv == -1 && (errno == EINTR))
  210 + continue;
  211 + if (rv == -1)
  212 + exit(1);
  213 + if (rv == 0)
  214 + break;
  215 + n += rv;
  216 + }
  217 +
  218 + buf[c] = '\0';
  219 + printf("echo: %s\n", buf);
  220 + }
  221 + close(sockfd);
199 222 }
200   -
... ...