]>
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
));
53 * If there is a pid file already around, kill the previously running
54 * fakesmtp process. Hopefully this will reduce the race conditions
55 * that crop up when running the test suite.
58 if (stat(PIDFILE
, &st
) == 0) {
61 if (!(pid
= fopen(PIDFILE
, "r"))) {
62 fprintf(stderr
, "Cannot open " PIDFILE
63 " (%s), continuing ...\n", strerror(errno
));
65 rc
= fscanf(pid
, "%ld", &oldpid
);
69 fprintf(stderr
, "Unable to parse pid in "
70 PIDFILE
", continuing ...\n");
72 kill((pid_t
) oldpid
, SIGTERM
);
79 memset(&hints
, 0, sizeof(hints
));
81 hints
.ai_family
= PF_INET
;
82 hints
.ai_socktype
= SOCK_STREAM
;
83 hints
.ai_protocol
= IPPROTO_TCP
;
84 hints
.ai_flags
= AI_PASSIVE
;
86 rc
= getaddrinfo("127.0.0.1", argv
[2], &hints
, &res
);
89 fprintf(stderr
, "Unable to resolve localhost/%s: %s\n",
90 argv
[2], gai_strerror(rc
));
94 l
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
97 fprintf(stderr
, "Unable to create listening socket: %s\n",
104 if (setsockopt(l
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1) {
105 fprintf(stderr
, "Unable to set SO_REUSEADDR: %s\n",
110 if (bind(l
, res
->ai_addr
, res
->ai_addrlen
) == -1) {
111 fprintf(stderr
, "Unable to bind socket: %s\n", strerror(errno
));
115 if (listen(l
, 1) == -1) {
116 fprintf(stderr
, "Unable to listen on socket: %s\n",
122 * Now that our socket & files are set up, wait 30 seconds for
123 * a connection. If there isn't one, then exit.
126 if (!(pid
= fopen(PIDFILE
, "w"))) {
127 fprintf(stderr
, "Cannot open " PIDFILE
": %s\n",
132 fprintf(pid
, "%ld\n", (long) getpid());
135 signal(SIGTERM
, handleterm
);
143 rc
= select(l
+ 1, &readfd
, NULL
, NULL
, &tv
);
146 fprintf(stderr
, "select() failed: %s\n", strerror(errno
));
151 * I think if we get a timeout, we should just exit quietly.
159 * Alright, got a connection! Accept it.
162 if ((conn
= accept(l
, NULL
, NULL
)) == -1) {
163 fprintf(stderr
, "Unable to accept connection: %s\n",
171 * Pretend to be an SMTP server.
174 putsmtp(conn
, "220 Not really an ESMTP server");
180 rc
= getsmtp(conn
, line
);
185 fprintf(f
, "%s\n", line
);
188 * If we're in DATA mode, then check to see if we've got
189 * a "."; otherwise, continue
193 if (strcmp(line
, ".") == 0) {
195 putsmtp(conn
, "250 Thanks for the info!");
201 * Most commands we ignore and send the same response to.
204 if (strcmp(line
, "QUIT") == 0) {
205 putsmtp(conn
, "221 Later alligator!");
208 } else if (strcmp(line
, "DATA") == 0) {
209 putsmtp(conn
, "354 Go ahead");
212 putsmtp(conn
, "250 I'll buy that for a dollar!");
222 * Write a line to the SMTP client on the other end
226 putsmtp(int socket
, char *data
)
230 iov
[0].iov_base
= data
;
231 iov
[0].iov_len
= strlen(data
);
232 iov
[1].iov_base
= "\r\n";
235 writev(socket
, iov
, 2);
239 * Read a line (up to the \r\n)
243 getsmtp(int socket
, char *data
)
246 static unsigned int bytesinbuf
= 0;
247 static char buffer
[LINESIZE
* 2], *p
;
254 if (bytesinbuf
> 0 && (p
= strchr(buffer
, '\r')) &&
257 strncpy(data
, buffer
, LINESIZE
);
258 data
[LINESIZE
- 1] = '\0';
262 * Shuffle leftover bytes back to the beginning
265 bytesinbuf
-= cc
+ 2; /* Don't forget \r\n */
266 if (bytesinbuf
> 0) {
267 memmove(buffer
, buffer
+ cc
+ 2, bytesinbuf
);
272 if (bytesinbuf
>= sizeof(buffer
)) {
273 fprintf(stderr
, "Buffer overflow in getsmtp()!\n");
277 memset(buffer
+ bytesinbuf
, 0, sizeof(buffer
) - bytesinbuf
);
278 cc
= read(socket
, buffer
+ bytesinbuf
,
279 sizeof(buffer
) - bytesinbuf
);
282 fprintf(stderr
, "Read failed: %s\n", strerror(errno
));
298 handleterm(int signal
)
308 * Get rid of our pid file