]>
diplodocus.org Git - nmh/blob - test/fakesmtp.c
2 * fakesmtp - A fake SMTP server used by the nmh test suite
4 * This code is Copyright (c) 2012, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
15 #include <sys/socket.h>
16 #include <sys/types.h>
17 #include <sys/select.h>
22 #define PIDFILE "/tmp/fakesmtp.pid"
26 static void killpidfile(void);
27 static void handleterm(int);
28 static void putsmtp(int, char *);
29 static int getsmtp(int, char *);
32 main(int argc
, char *argv
[])
34 struct addrinfo hints
, *res
;
35 int rc
, l
, conn
, on
, datamode
;
42 fprintf(stderr
, "Usage: %s output-filename port\n", argv
[0]);
46 if (!(f
= fopen(argv
[1], "w"))) {
47 fprintf(stderr
, "Unable to open output file \"%s\": %s\n",
48 argv
[1], strerror(errno
));
52 memset(&hints
, 0, sizeof(hints
));
54 hints
.ai_family
= PF_INET
;
55 hints
.ai_socktype
= SOCK_STREAM
;
56 hints
.ai_protocol
= IPPROTO_TCP
;
57 hints
.ai_flags
= AI_PASSIVE
;
59 rc
= getaddrinfo("127.0.0.1", argv
[2], &hints
, &res
);
62 fprintf(stderr
, "Unable to resolve localhost/%s: %s\n",
63 argv
[2], gai_strerror(rc
));
67 l
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
70 fprintf(stderr
, "Unable to create listening socket: %s\n",
77 if (setsockopt(l
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1) {
78 fprintf(stderr
, "Unable to set SO_REUSEADDR: %s\n",
83 if (bind(l
, res
->ai_addr
, res
->ai_addrlen
) == -1) {
84 fprintf(stderr
, "Unable to bind socket: %s\n", strerror(errno
));
88 if (listen(l
, 1) == -1) {
89 fprintf(stderr
, "Unable to listen on socket: %s\n",
95 * Now that our socket & files are set up, do the following things:
97 * - Check for a PID file. If there is one, kill the old version.
98 * - Wait 30 seconds for a connection. If there isn't one, then
102 if (stat(PIDFILE
, &st
) == 0) {
105 if (!(pid
= fopen(PIDFILE
, "r"))) {
106 fprintf(stderr
, "Cannot open " PIDFILE
107 " (%s), continuing ...\n", strerror(errno
));
109 rc
= fscanf(pid
, "%ld", &oldpid
);
113 fprintf(stderr
, "Unable to parse pid in "
114 PIDFILE
", continuing ...\n");
116 kill((pid_t
) oldpid
, SIGTERM
);
123 if (!(pid
= fopen(PIDFILE
, "w"))) {
124 fprintf(stderr
, "Cannot open " PIDFILE
": %s\n",
129 fprintf(pid
, "%ld\n", (long) getpid());
132 signal(SIGTERM
, handleterm
);
140 rc
= select(l
+ 1, &readfd
, NULL
, NULL
, &tv
);
143 fprintf(stderr
, "select() failed: %s\n", strerror(errno
));
148 * I think if we get a timeout, we should just exit quietly.
156 * Alright, got a connection! Accept it.
159 if ((conn
= accept(l
, NULL
, NULL
)) == -1) {
160 fprintf(stderr
, "Unable to accept connection: %s\n",
168 * Pretend to be an SMTP server.
171 putsmtp(conn
, "220 Not really an ESMTP server");
177 rc
= getsmtp(conn
, line
);
182 fprintf(f
, "%s\n", line
);
185 * If we're in DATA mode, then check to see if we've got
186 * a "."; otherwise, continue
190 if (strcmp(line
, ".") == 0) {
192 putsmtp(conn
, "250 Thanks for the info!");
198 * Most commands we ignore and send the same response to.
201 if (strcmp(line
, "QUIT") == 0) {
202 putsmtp(conn
, "221 Later alligator!");
205 } else if (strcmp(line
, "DATA") == 0) {
206 putsmtp(conn
, "354 Go ahead");
209 putsmtp(conn
, "250 I'll buy that for a dollar!");
219 * Write a line to the SMTP client on the other end
223 putsmtp(int socket
, char *data
)
227 iov
[0].iov_base
= data
;
228 iov
[0].iov_len
= strlen(data
);
229 iov
[1].iov_base
= "\r\n";
232 writev(socket
, iov
, 2);
236 * Read a line (up to the \r\n)
240 getsmtp(int socket
, char *data
)
243 static unsigned int bytesinbuf
= 0;
244 static char buffer
[LINESIZE
* 2], *p
;
251 if (bytesinbuf
> 0 && (p
= strchr(buffer
, '\r')) &&
254 strncpy(data
, buffer
, LINESIZE
);
255 data
[LINESIZE
- 1] = '\0';
259 * Shuffle leftover bytes back to the beginning
262 bytesinbuf
-= cc
+ 2; /* Don't forget \r\n */
263 if (bytesinbuf
> 0) {
264 memmove(buffer
, buffer
+ cc
+ 2, bytesinbuf
);
269 if (bytesinbuf
>= sizeof(buffer
)) {
270 fprintf(stderr
, "Buffer overflow in getsmtp()!\n");
274 memset(buffer
+ bytesinbuf
, 0, sizeof(buffer
) - bytesinbuf
);
275 cc
= read(socket
, buffer
+ bytesinbuf
,
276 sizeof(buffer
) - bytesinbuf
);
279 fprintf(stderr
, "Read failed: %s\n", strerror(errno
));
295 handleterm(int signal
)
305 * Get rid of our pid file