1 #include <ccan/oserver/oserver.h>
2 #include <ccan/read_write_all/read_write_all.h>
3 #include <ccan/opt/opt.h>
4 #include <ccan/tevent/tevent.h>
5 #include <ccan/array_size/array_size.h>
6 #include <ccan/noerr/noerr.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <netinet/tcp.h>
21 RECEIVING_USER_QUESTION,
26 static uint16_t state_flag_map[] = {
27 [RECEIVING_USER_QUESTION] = TEVENT_FD_READ,
28 [SENDING_ANSWER] = TEVENT_FD_WRITE,
33 /* What are we doing today, brain? */
35 /* Our event info, and the file descriptor. */
36 struct tevent_fd *fde;
38 /* The question we read from client. */
40 /* How many bytes of the reply we sent so far. */
44 /* 5 clients should be enough for anybody! */
45 static struct client *clients[5];
47 static struct tevent_fd *sfde;
49 static ssize_t write_string(int fd, const char *str)
51 return write(fd, str, strlen(str));
54 static ssize_t read_string(int fd, char **buf)
56 ssize_t ret, len, maxlen;
59 maxlen = talloc_array_length(*buf);
61 if (maxlen < len + 100) {
63 *buf = talloc_realloc(NULL, *buf, char, maxlen);
66 ret = read(fd, *buf + len, maxlen - len - 1);
68 (*buf)[len + ret] = '\0';
72 static bool input_finished(const char *str)
74 return strchr(str, '\n');
77 /* Update state, and set our READ/WRITE flags appropriately. */
78 static void set_state(struct client *c, enum state state)
81 tevent_fd_set_flags(c->fde, state_flag_map[state]);
84 /* Returns false on error, increments state on finishing string. */
85 static bool send_string(struct client *c, const char *str)
87 ssize_t len = write_string(c->fd, str + c->bytes_sent);
91 if (c->bytes_sent == strlen(str)) {
93 set_state(c, c->state+1);
98 static void service_client(struct tevent_context *ev,
99 struct tevent_fd *fde, uint16_t flags, void *_c)
101 struct client *c = _c;
105 case RECEIVING_USER_QUESTION:
106 len = read_string(c->fd, &c->question);
109 if (input_finished(c->question)) {
112 for (i = 0; c->question[i]; i++)
113 c->question[i] = toupper(c->question[i]);
114 set_state(c, SENDING_ANSWER);
118 if (!send_string(c, c->question))
125 if (c->state != FINISHED)
132 static int cleanup_client(struct client *client)
136 for (i = 0; i < ARRAY_SIZE(clients); i++) {
137 if (clients[i] == client) {
139 tevent_fd_set_flags(sfde, TEVENT_FD_READ);
146 static void add_client(struct tevent_context *ev,
147 struct tevent_fd *fde, uint16_t flags, void *unused)
149 struct client *client;
152 client = talloc(sfde, struct client);
153 client->fd = accept(sfd, NULL, 0);
155 err(1, "Accepting client connection");
157 client->state = RECEIVING_USER_QUESTION;
158 client->bytes_sent = 0;
159 client->question = talloc_strdup(client, "");
160 client->fde = tevent_add_fd(ev, client, client->fd,
161 state_flag_map[client->state],
162 service_client, client);
163 tevent_fd_set_auto_close(client->fde);
165 /* Find empty slot in array for this client. */
166 for (i = 0; clients[i]; i++);
168 talloc_set_destructor(client, cleanup_client);
170 /* Full? Stop listening... */
171 if (i == ARRAY_SIZE(clients)-1)
172 tevent_fd_set_flags(sfde, 0);
175 void *oserver_setup(struct tevent_context *ev, unsigned short port)
179 struct sockaddr addr;
180 struct sockaddr_in in;
183 sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
187 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
188 warn("Setting socket reuse");
190 u.in.sin_family = AF_INET;
191 u.in.sin_port = htons(port);
192 u.in.sin_addr.s_addr = INADDR_ANY;
193 if (bind(sfd, &u.addr, sizeof(u.in)) == -1) {
198 if (listen(sfd, 0) != 0) {
203 sfde = tevent_add_fd(ev, ev, sfd, TEVENT_FD_READ, add_client, NULL);
204 tevent_fd_set_auto_close(sfde);
206 /* Don't kill us if client dies. */
207 signal(SIGPIPE, SIG_IGN);