1 /*
2  * libmowgli: A collection of useful routines for programming.
3  * echoserver.c: Testing of the I/O system
4  *
5  * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
12  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
15  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
19  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
20  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21  * POSSIBILITY OF SUCH DAMAGE.
22  */
23 
24 #include <mowgli.h>
25 
26 mowgli_eventloop_t *base_eventloop;
27 mowgli_eventloop_pollable_t *listener;
28 
29 typedef struct
30 {
31 	mowgli_eventloop_io_t *io;
32 	char buf[1024];
33 } client_t;
34 
35 #ifdef DEBUG
36 static void
timer_tick(void * unused)37 timer_tick(void *unused)
38 {
39 	static int ticks = 0;
40 
41 	printf("tick: %d\n", ++ticks);
42 }
43 
44 #endif
45 
46 static int
setup_listener(void)47 setup_listener(void)
48 {
49 	struct sockaddr_in in = { };
50 	int fd = socket(AF_INET, SOCK_STREAM, 0);
51 
52 	in.sin_family = AF_INET;
53 	in.sin_port = htons(1337);
54 
55 	if (bind(fd, (struct sockaddr *) &in, sizeof(struct sockaddr_in)) < 0)
56 	{
57 		in.sin_port = htons(31337);
58 		bind(fd, (struct sockaddr *) &in, sizeof(struct sockaddr_in));
59 	}
60 
61 	listen(fd, 5);
62 
63 	return fd;
64 }
65 
66 static void
write_data(mowgli_eventloop_t * eventloop,mowgli_eventloop_io_t * io,mowgli_eventloop_io_dir_t dir,void * userdata)67 write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata)
68 {
69 	mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io);
70 	client_t *client = userdata;
71 
72 	if (*client->buf)
73 		send(pollable->fd, client->buf, strlen(client->buf), 0);
74 
75 	memset(client->buf, '\0', sizeof(client->buf));
76 
77 	mowgli_pollable_setselect(base_eventloop, client->io, MOWGLI_EVENTLOOP_IO_WRITE, NULL);
78 }
79 
80 static void
read_data(mowgli_eventloop_t * eventloop,mowgli_eventloop_io_t * io,mowgli_eventloop_io_dir_t dir,void * userdata)81 read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata)
82 {
83 	mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io);
84 	int ret;
85 
86 	client_t *client = userdata;
87 
88 	if ((ret = recv(pollable->fd, client->buf, sizeof(client->buf), 0)) <= 0)
89 	{
90 		mowgli_free(client);
91 		mowgli_pollable_destroy(eventloop, io);
92 
93 		return;
94 	}
95 
96 	mowgli_pollable_setselect(base_eventloop, client->io, MOWGLI_EVENTLOOP_IO_WRITE, write_data);
97 }
98 
99 static void
client_error(mowgli_eventloop_t * eventloop,mowgli_eventloop_io_t * io,mowgli_eventloop_io_dir_t dir,void * userdata)100 client_error(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata)
101 {
102 	mowgli_free(userdata);
103 	mowgli_pollable_destroy(eventloop, io);
104 }
105 
106 static void
accept_client(mowgli_eventloop_t * eventloop,mowgli_eventloop_io_t * io,mowgli_eventloop_io_dir_t dir,void * userdata)107 accept_client(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata)
108 {
109 	mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io);
110 	client_t *client;
111 	mowgli_descriptor_t new_fd, listener_fd;
112 
113 	listener_fd = pollable->fd;
114 
115 	new_fd = accept(listener_fd, NULL, NULL);
116 
117 	client = mowgli_alloc(sizeof(client_t));
118 
119 	client->io = mowgli_pollable_create(eventloop, new_fd, client);
120 	mowgli_pollable_set_nonblocking(client->io, true);
121 
122 	mowgli_pollable_setselect(base_eventloop, client->io, MOWGLI_EVENTLOOP_IO_READ, read_data);
123 	mowgli_pollable_setselect(base_eventloop, client->io, MOWGLI_EVENTLOOP_IO_ERROR, client_error);
124 }
125 
126 int
main(int argc,char * argv[])127 main(int argc, char *argv[])
128 {
129 	int fd;
130 
131 	base_eventloop = mowgli_eventloop_create();
132 
133 #ifdef DEBUG
134 	mowgli_timer_add(base_eventloop, "timer_tick", timer_tick, NULL, 1);
135 #endif
136 
137 	fd = setup_listener();
138 
139 	listener = mowgli_pollable_create(base_eventloop, fd, NULL);
140 	mowgli_pollable_set_nonblocking(listener, true);
141 	mowgli_pollable_setselect(base_eventloop, listener, MOWGLI_EVENTLOOP_IO_READ, accept_client);
142 
143 	mowgli_eventloop_run(base_eventloop);
144 
145 	mowgli_eventloop_destroy(base_eventloop);
146 
147 	return EXIT_SUCCESS;
148 }
149