7 /* multi-threaded QMQP test server
10 /* \fBqmqp-sink\fR [\fB-46cv\fR] [\fB-x \fItime\fR]
11 /* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR
13 /* \fBqmqp-sink\fR [\fB-46cv\fR] [\fB-x \fItime\fR]
14 /* \fBunix:\fR\fIpathname\fR \fIbacklog\fR
16 /* \fBqmqp-sink\fR listens on the named host (or address) and port.
17 /* It receives messages from the network and throws them away.
18 /* The purpose is to measure QMQP client performance, not protocol
20 /* Connections can be accepted on IPv4 or IPv6 endpoints, or on
21 /* UNIX-domain sockets.
22 /* IPv4 and IPv6 are the default.
23 /* This program is the complement of the \fBqmqp-source\fR(1) program.
25 /* Note: this is an unsupported test program. No attempt is made
26 /* to maintain compatibility between successive versions.
30 /* Support IPv4 only. This option has no effect when
31 /* Postfix is built without IPv6 support.
33 /* Support IPv6 only. This option is not available when
34 /* Postfix is built without IPv6 support.
36 /* Display a running counter that is updated whenever a delivery
39 /* Increase verbosity. Specify \fB-v -v\fR to see some of the QMQP
41 /* .IP "\fB-x \fItime\fR
42 /* Terminate after \fItime\fR seconds. This is to facilitate memory
45 /* qmqp-source(1), QMQP message generator
49 /* The Secure Mailer license must be distributed with this software.
52 /* IBM T.J. Watson Research
54 /* Yorktown Heights, NY 10598, USA
60 #include <sys/socket.h>
68 /* Utility library. */
77 #include <msg_vstream.h>
78 #include <netstring.h>
79 #include <inet_proto.h>
83 #include <qmqp_proto.h>
84 #include <mail_version.h>
86 /* Application-specific. */
89 VSTREAM
*stream
; /* client connection */
90 int count
; /* bytes to go */
94 static VSTRING
*buffer
;
95 static void disconnect(SINK_STATE
*);
96 static int count_deliveries
;
99 /* send_reply - finish conversation */
101 static void send_reply(SINK_STATE
*state
)
103 vstring_sprintf(buffer
, "%cOk", QMQP_STAT_OK
);
104 NETSTRING_PUT_BUF(state
->stream
, buffer
);
105 netstring_fflush(state
->stream
);
106 if (count_deliveries
) {
108 vstream_printf("%d\r", counter
);
109 vstream_fflush(VSTREAM_OUT
);
114 /* read_data - read over-all netstring data */
116 static void read_data(int unused_event
, char *context
)
118 SINK_STATE
*state
= (SINK_STATE
*) context
;
119 int fd
= vstream_fileno(state
->stream
);
123 * Refill the VSTREAM buffer, if necessary.
125 if (VSTREAM_GETC(state
->stream
) == VSTREAM_EOF
)
126 netstring_except(state
->stream
, vstream_ftimeout(state
->stream
) ?
127 NETSTRING_ERR_TIME
: NETSTRING_ERR_EOF
);
131 * Flush the VSTREAM buffer. As documented, vstream_fseek() discards
134 if ((count
= vstream_peek(state
->stream
)) > 0) {
135 state
->count
-= count
;
136 if (state
->count
<= 0) {
140 vstream_fseek(state
->stream
, 0L, 0);
144 * Do not block while waiting for the arrival of more data.
146 event_disable_readwrite(fd
);
147 event_enable_read(fd
, read_data
, context
);
150 /* read_length - read over-all netstring length */
152 static void read_length(int event
, char *context
)
154 SINK_STATE
*state
= (SINK_STATE
*) context
;
156 switch (vstream_setjmp(state
->stream
)) {
159 msg_panic("unknown error reading input");
161 case NETSTRING_ERR_TIME
:
162 msg_panic("attempt to read non-readable socket");
165 case NETSTRING_ERR_EOF
:
166 msg_warn("lost connection");
170 case NETSTRING_ERR_FORMAT
:
171 msg_warn("netstring format error");
175 case NETSTRING_ERR_SIZE
:
176 msg_warn("netstring size error");
181 * Include the netstring terminator in the read byte count. This
182 * violates abstractions.
185 state
->count
= netstring_get_length(state
->stream
) + 1;
186 read_data(event
, context
);
191 /* disconnect - handle disconnection events */
193 static void disconnect(SINK_STATE
*state
)
195 event_disable_readwrite(vstream_fileno(state
->stream
));
196 vstream_fclose(state
->stream
);
197 myfree((char *) state
);
200 /* connect_event - handle connection events */
202 static void connect_event(int unused_event
, char *context
)
204 int sock
= CAST_CHAR_PTR_TO_INT(context
);
206 SOCKADDR_SIZE len
= sizeof(sa
);
210 if ((fd
= accept(sock
, &sa
, &len
)) >= 0) {
212 msg_info("connect (%s)",
214 sa
.sa_family
== AF_LOCAL
? "AF_LOCAL" :
216 sa
.sa_family
== AF_UNIX
? "AF_UNIX" :
218 sa
.sa_family
== AF_INET
? "AF_INET" :
220 sa
.sa_family
== AF_INET6
? "AF_INET6" :
222 "unknown protocol family");
223 non_blocking(fd
, NON_BLOCKING
);
224 state
= (SINK_STATE
*) mymalloc(sizeof(*state
));
225 state
->stream
= vstream_fdopen(fd
, O_RDWR
);
226 netstring_setup(state
->stream
, var_tmout
);
227 event_enable_read(fd
, read_length
, (char *) state
);
231 /* terminate - voluntary exit */
233 static void terminate(int unused_event
, char *unused_context
)
238 /* usage - explain */
240 static void usage(char *myname
)
242 msg_fatal("usage: %s [-cv] [-x time] [host]:port backlog", myname
);
245 MAIL_VERSION_STAMP_DECLARE
;
247 int main(int argc
, char **argv
)
253 const char *protocols
= INET_PROTO_NAME_ALL
;
254 INET_PROTO_INFO
*proto_info
;
257 * Fingerprint executables and core dumps.
259 MAIL_VERSION_STAMP_ALLOCATE
;
264 signal(SIGPIPE
, SIG_IGN
);
267 * Initialize diagnostics.
269 msg_vstream_init(argv
[0], VSTREAM_ERR
);
274 while ((ch
= GETOPT(argc
, argv
, "46cvx:")) > 0) {
277 protocols
= INET_PROTO_NAME_IPV4
;
280 protocols
= INET_PROTO_NAME_IPV6
;
289 if ((ttl
= atoi(optarg
)) <= 0)
291 event_request_timer(terminate
, (char *) 0, ttl
);
297 if (argc
- optind
!= 2)
299 if ((backlog
= atoi(argv
[optind
+ 1])) <= 0)
305 proto_info
= inet_proto_init("protocols", protocols
);
306 buffer
= vstring_alloc(1024);
307 if (strncmp(argv
[optind
], "unix:", 5) == 0) {
308 sock
= unix_listen(argv
[optind
] + 5, backlog
, BLOCKING
);
310 if (strncmp(argv
[optind
], "inet:", 5) == 0)
312 sock
= inet_listen(argv
[optind
], backlog
, BLOCKING
);
316 * Start the event handler.
318 event_enable_read(sock
, connect_event
, CAST_INT_TO_CHAR_PTR(sock
));