Skip to content

Commit 065e3f5

Browse files
committed
added celluloid benchmark
1 parent b56b1fd commit 065e3f5

File tree

76 files changed

+1624
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1624
-20
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.DS_Store
2+
Gemfile.lock
3+
*.6
4+
*.beam
5+
*.jar

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ All implementations have roughly the same functionality, which is at the "hello
4949
bundle
5050
ruby smtpd.rb
5151

52+
### Ruby - Celluloid
53+
54+
cd ruby-celluloid
55+
bundle
56+
ruby smtpd.rb
57+
5258
## Performance testing
5359

5460
Performance testing with smtpsource. This program is distributed with Postfix.

c/Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CC=gcc
2+
CFLAGS=
3+
LIBS=-levent
4+
SRCS=smtpd.c
5+
TARG=smtpd
6+
7+
.PHONY: all
8+
all: $(TARG)
9+
10+
$(TARG):
11+
$(CC) $(CFLAGS) $(LIBS) $(SRCS) -o $(TARG)
12+
13+
clean:
14+
rm -f *.o $(TARG)
15+

c/smtpd.c

+315
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
/*
2+
* SMTP Daemon in C with libevent
3+
*
4+
* Compile with:
5+
* cc -I/usr/local/include -o smtpd smtpd.c -L/usr/local/lib -levent
6+
*
7+
* Copyright (c) 2007-2012 Maarten Oelering
8+
*/
9+
10+
#include <sys/types.h>
11+
#include <sys/socket.h>
12+
#include <netinet/in.h>
13+
#include <arpa/inet.h>
14+
15+
/* Required by event.h. */
16+
#include <sys/time.h>
17+
18+
#include <stdlib.h>
19+
#include <stdio.h>
20+
#include <string.h>
21+
#include <fcntl.h>
22+
#include <unistd.h>
23+
#include <errno.h>
24+
#include <err.h>
25+
26+
/* Libevent. */
27+
#include <event.h>
28+
29+
/* Port to listen on. */
30+
#define SERVER_PORT 2525
31+
32+
/* states */
33+
#define WAIT_EHLO 1
34+
#define WAIT_MAIL 2
35+
#define WAIT_RCPT 3
36+
#define WAIT_DATA 4
37+
#define WAIT_QUIT 5
38+
39+
/**
40+
* A struct for client specific data, also includes pointer to create
41+
* a list of clients.
42+
*/
43+
struct client {
44+
/* The clients socket. */
45+
int fd;
46+
47+
/* The bufferedevent for this client. */
48+
struct bufferevent *buf_ev;
49+
50+
int state;
51+
52+
/* info received from client */
53+
char* ip;
54+
char* hostname;
55+
char* mail_from;
56+
char** rcpt_to;
57+
char* data;
58+
};
59+
60+
/*
61+
* Compile with:
62+
* cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
63+
*/
64+
65+
/**
66+
* Set a socket to non-blocking mode.
67+
*/
68+
int
69+
setnonblock(int fd)
70+
{
71+
int flags;
72+
73+
/* ??? WIN32: use ioctlsocket() */
74+
flags = fcntl(fd, F_GETFL);
75+
if (flags < 0)
76+
return flags;
77+
flags |= O_NONBLOCK;
78+
if (fcntl(fd, F_SETFL, flags) < 0)
79+
return -1;
80+
81+
return 0;
82+
}
83+
84+
void write_banner(struct client* client)
85+
{
86+
char message[1024]; /* static ? */
87+
snprintf(message, sizeof(message), "220 %s ESMTP %s\r\n", "hostname", "version");
88+
89+
bufferevent_write(client->buf_ev, message, strlen(message));
90+
}
91+
92+
void write_ehlo_rsp(struct client* client)
93+
{
94+
char message[1024]; /* static ? */
95+
snprintf(message, sizeof(message), "250-%s\r\n250-SIZE %s\r\n250 8BITMIME",
96+
"hostname", "maxsize");
97+
98+
bufferevent_write(client->buf_ev, message, strlen(message));
99+
}
100+
101+
/**
102+
* Called by libevent when there is data to read.
103+
*/
104+
void
105+
buffered_on_read(struct bufferevent *bev, void *arg)
106+
{
107+
struct client *client = (struct client *)arg;
108+
char* line;
109+
110+
printf("buffered_on_read\n");
111+
line = evbuffer_readline(bev->input);
112+
printf("%s\n", line);
113+
114+
if (strncasecmp(line, "HELO", 4) == 0)
115+
{
116+
/* we expect EHLO */
117+
}
118+
else if (strncasecmp(line, "EHLO", 4) == 0)
119+
{
120+
if (client->state == WAIT_EHLO)
121+
{
122+
write_ehlo_rsp(client);
123+
client->state = WAIT_MAIL;
124+
}
125+
}
126+
else if (strncasecmp(line, "MAIL", 4) == 0)
127+
{
128+
/* we don't allow skipping EHLO */
129+
/* "503 5.5.1 Error: send HELO/EHLO first" */
130+
/* "501 5.5.4 Syntax: MAIL FROM:<address>" */
131+
/* "501 5.1.7 Bad sender address syntax" */
132+
/* expect BODY=8BITMIME, BODY=7BIT, SIZE=, RET=, ENVID= */
133+
/* 250 2.1.0 Ok */
134+
}
135+
else if (strncasecmp(line, "RCPT", 4) == 0)
136+
{
137+
/* "250 Ok" */
138+
/* "501 Error: invalid address" */
139+
}
140+
else if (strncasecmp(line, "DATA", 4) == 0)
141+
{
142+
/* "354 End data with <CR><LF>.<CR><LF>" */
143+
/* 250 Ok: queued as 7BABF7B086 */
144+
}
145+
else if (strncasecmp(line, "RSET", 4) == 0)
146+
{
147+
/*
148+
* Restore state to right after HELO/EHLO command.
149+
*/
150+
/* "250 2.0.0 Ok" */
151+
/* no parameters allowed "501 5.5.4 Syntax: RSET" */
152+
}
153+
else if (strncasecmp(line, "NOOP", 4) == 0)
154+
{
155+
/* RFC 2821 says that NOOP can have a parameter string which is to be ignored */
156+
/* "250 2.0.0 Ok" */
157+
}
158+
else if (strncasecmp(line, "QUIT", 4) == 0)
159+
{
160+
/* "221 2.0.0 Bye" */
161+
}
162+
else
163+
{
164+
/* "502 Error: command not implemented" */
165+
}
166+
}
167+
168+
/**
169+
* Called by libevent when the write buffer reaches 0. We only
170+
* provide this because libevent expects it, but we don't use it.
171+
*/
172+
void
173+
buffered_on_write(struct bufferevent *bev, void *arg)
174+
{
175+
printf("buffered_on_write\n");
176+
}
177+
178+
/**
179+
* Called by libevent when there is an error on the underlying socket
180+
* descriptor.
181+
*/
182+
void
183+
buffered_on_error(struct bufferevent *bev, short what, void *arg)
184+
{
185+
struct client *client = (struct client *)arg;
186+
187+
if (what & EVBUFFER_EOF) {
188+
/* Client disconnected, remove the read event and the
189+
* free the client structure. */
190+
printf("Client disconnected.\n");
191+
}
192+
else {
193+
warn("Client socket error, disconnecting.\n");
194+
}
195+
bufferevent_free(client->buf_ev);
196+
/* close client socket */
197+
close(client->fd);
198+
free(client);
199+
}
200+
201+
/*
202+
*/
203+
void
204+
on_accept(int fd, short ev, void *arg)
205+
{
206+
int client_fd;
207+
struct sockaddr_in client_addr;
208+
socklen_t client_len = sizeof(client_addr);
209+
struct client *client;
210+
char* client_ip;
211+
212+
/* return next completed connection */
213+
client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
214+
if (client_fd < 0) {
215+
warn("accept failed");
216+
return;
217+
}
218+
219+
client_ip = inet_ntoa(client_addr.sin_addr);
220+
printf("Accepted connection from %s\n", client_ip);
221+
222+
/* Set the client socket to non-blocking mode. */
223+
if (setnonblock(client_fd) < 0)
224+
warn("failed to set client socket non-blocking");
225+
226+
/* We've accepted a new client, create a client object. */
227+
client = calloc(1, sizeof(*client));
228+
if (client == NULL)
229+
err(1, "malloc failed");
230+
client->fd = client_fd;
231+
232+
/* save client ip address */
233+
client->ip = client_ip;
234+
235+
client->state = WAIT_EHLO;
236+
237+
/*
238+
* Create a new buffered event object.
239+
*
240+
* The read callback is invoked whenever we read new data.
241+
* The write callback is invoked whenever the output buffer is drained.
242+
* The error callback is invoked on a write/read error or on EOF.
243+
* Also sets EV_WRITE.
244+
*/
245+
client->buf_ev = bufferevent_new(client_fd, buffered_on_read,
246+
buffered_on_write, buffered_on_error, client);
247+
248+
/* We have to enable it before our callbacks will be
249+
* called. */
250+
bufferevent_enable(client->buf_ev, EV_READ);
251+
252+
write_banner(client);
253+
}
254+
255+
static int
256+
make_socket(int port)
257+
{
258+
int listen_fd;
259+
struct sockaddr_in listen_addr;
260+
int reuseaddr_on;
261+
262+
/* create socket of family IPv4 and type TCP */
263+
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
264+
if (listen_fd < 0)
265+
err(1, "listen failed");
266+
267+
/* allow local address reuse */
268+
/* ??? should be called between socket and bind */
269+
reuseaddr_on = 1;
270+
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on));
271+
/* ??? SO_LINGER */
272+
273+
/* assign local protocol address to socket */
274+
memset(&listen_addr, 0, sizeof(listen_addr));
275+
listen_addr.sin_family = AF_INET;
276+
listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* bind to any IP */
277+
listen_addr.sin_port = htons(port);
278+
if (bind(listen_fd, (struct sockaddr *) &listen_addr, sizeof(listen_addr)) < 0)
279+
err(1, "bind failed");
280+
281+
/* convert socket to listening with backlog size of 5 */
282+
if (listen(listen_fd, 5) < 0)
283+
err(1, "listen failed");
284+
285+
/* Set the socket to non-blocking, this is essential in event
286+
* based programming with libevent. */
287+
288+
/* ??? do after socket() */
289+
if (setnonblock(listen_fd) < 0)
290+
err(1, "failed to set server socket to non-blocking");
291+
292+
return listen_fd;
293+
}
294+
295+
int
296+
main(int argc, char **argv)
297+
{
298+
int listen_fd;
299+
struct event ev_accept;
300+
301+
/* Initialize libevent. */
302+
event_init();
303+
304+
listen_fd = make_socket(SERVER_PORT);
305+
306+
/* We now have a listening socket, we create a read event to
307+
* be notified when a client connects. */
308+
event_set(&ev_accept, listen_fd, EV_READ|EV_PERSIST, on_accept, NULL);
309+
event_add(&ev_accept, NULL);
310+
311+
/* Start the event loop. */
312+
event_dispatch();
313+
314+
return 0;
315+
}

go/smtpd

3.23 MB
Binary file not shown.

java-netty/out/SmtpServer.class

1.16 KB
Binary file not shown.
3.61 KB
Binary file not shown.
1.12 KB
Binary file not shown.

java-nio2/compile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
rm -fr out
2+
mkdir out
3+
javac -d out src/AsynchronousConnection.java src/AsynchronousConnectionHandler.java src/ByteBuffers.java src/SmtpCommand.java src/SmtpConnection.java src/SmtpReply.java src/SmtpServer.java src/SmtpSession.java
4+
217 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3.31 KB
Binary file not shown.
321 Bytes
Binary file not shown.

java-nio2/out/ByteBuffers.class

2.58 KB
Binary file not shown.

java-nio2/out/SmtpCommand$1.class

632 Bytes
Binary file not shown.

java-nio2/out/SmtpCommand$2.class

729 Bytes
Binary file not shown.

java-nio2/out/SmtpCommand$3.class

568 Bytes
Binary file not shown.

java-nio2/out/SmtpCommand$4.class

958 Bytes
Binary file not shown.

java-nio2/out/SmtpCommand$5.class

1.02 KB
Binary file not shown.

java-nio2/out/SmtpCommand$6.class

822 Bytes
Binary file not shown.

java-nio2/out/SmtpCommand$7.class

597 Bytes
Binary file not shown.

java-nio2/out/SmtpCommand$8.class

826 Bytes
Binary file not shown.

java-nio2/out/SmtpCommand.class

2.11 KB
Binary file not shown.

java-nio2/out/SmtpConnection.class

4 KB
Binary file not shown.

java-nio2/out/SmtpReply.class

2.98 KB
Binary file not shown.

java-nio2/out/SmtpServer$1.class

1.89 KB
Binary file not shown.

java-nio2/out/SmtpServer.class

3.44 KB
Binary file not shown.

java-nio2/out/SmtpSession.class

448 Bytes
Binary file not shown.

java-nio2/smtpd

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
java -classpath "out/" SmtpServer

0 commit comments

Comments
 (0)