Compare commits
1 Commits
pre-5
...
tags/pre-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9adb6fcbee |
@@ -1,22 +1,3 @@
|
||||
2005-02-19 Dan Christian <robodan@idiom.com>
|
||||
|
||||
* Merge big Sendmail patch see ChangeLog-Sendmail for details
|
||||
|
||||
* src/bench.h (VERSION): Start working toward version 5.0 (now 4.9)
|
||||
|
||||
2004-09-07 Dan Christian <robodan@idiom.com>
|
||||
|
||||
* data/*.msg: Updated with more realistic messages
|
||||
|
||||
* bin/args.pl: Really fix doc link to be relative
|
||||
|
||||
* src/smtp.c (sendSMTPLoop): Handle file lists (random selection)
|
||||
(sendFile): New, send file with option offset and head/tail
|
||||
(SmtpFilePrep): Split a glob pattern to a list
|
||||
(SmtpFileInit): New, split out initial file scan
|
||||
|
||||
* src/bench.c (rangeNext): Get to last value in a random range
|
||||
|
||||
2004-06-14 Dan Christian <robodan@idiom.com>
|
||||
|
||||
* Makefile (VERSION): Bump version to 4.3
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
2005-02-03 Thom O'Connor <thom@sendmail.com>
|
||||
|
||||
* Merge Mozilla mstone HEAD with Sendmail,Inc. modifications. In
|
||||
particular, this included some hand-waving around the bitwise
|
||||
operators "leaveMailOnServer" in the Mozilla branch and the
|
||||
dinst_t struct pish->leaveMailOnServerDist.
|
||||
|
||||
2005-01-25 Thom O'Connor <thom@sendmail.com>
|
||||
|
||||
* Fix comments, properly attribute Sean O'Rourke's contributions.
|
||||
|
||||
2004-09-21 Thom O'Connor <thom@sendmail.com>
|
||||
|
||||
* Modified config/config.mk to build SSL version of mailclient.
|
||||
|
||||
2004-06-07 Thom O'Connor <thom@sendmail.com>
|
||||
|
||||
* Remove _thread_sys_poll defininition for poll in FreeBSD builds
|
||||
(bench.h).
|
||||
|
||||
2001-04-27 Sean O'Rourke <sean@sendmail.com>
|
||||
|
||||
* distributions can now be truncated. This is used to prevent
|
||||
0-recipient messages, and could be used to prevent enormous
|
||||
messages.
|
||||
|
||||
* throttling: Preload workloads use some additional mstone magic
|
||||
to throttle delivery rate based on server responsiveness. This is
|
||||
still in the experimental phase, and may change.
|
||||
|
||||
* fix for parsing bug exposed by distribution truncation notation.
|
||||
|
||||
2001-03-10 Sean O'Rourke <sean@sendmail.com>
|
||||
|
||||
* clients: Fixed up code for specifying client counts on a
|
||||
per-host or per-group basis. This eliminates the need to force
|
||||
the mozilla distribution code to do one's bidding.
|
||||
|
||||
* smtpsink.pl: Very basic threaded perl SMTP sink. This may go
|
||||
away to be replaced by the sink from smtpslam. Needs much better
|
||||
statistics.
|
||||
|
||||
2001-02-24 Sean O'Rourke <sean@sendmail.com>
|
||||
|
||||
* checksums added. See {checksum,md5}.{c,h}. Auto-generated
|
||||
messages can currently have checksums computed over the body, and
|
||||
pop and multipop retrieval will verify the sum.
|
||||
|
||||
2001-02-21 Sean O'Rourke <sean@sendmail.com>
|
||||
|
||||
* MIME generation changed to generate deep messages rather than
|
||||
several parts. This should be a better test of MIME parsers,
|
||||
forcing them to save more state.
|
||||
|
||||
2001-02-18 Sean O'Rourke <sean@sendmail.com>
|
||||
|
||||
* mstone_changes.html: update SSL documentation.
|
||||
|
||||
* wld, defaults.pm: divide the ever-expanding "config" section
|
||||
into more descriptive subparts: clients, server, sink, mstone.
|
||||
|
||||
* report: now in bin directory, where it should be.
|
||||
|
||||
2001-02-17 Sean O'Rourke <sean@sendmail.com>
|
||||
|
||||
* client.c, main.c, parse.c: removed old throttling code, as it
|
||||
wasn't being used.
|
||||
|
||||
* ALL: General code cleanup.
|
||||
|
||||
* sysdep.c: simplified rlimit-bumping code, added increase for
|
||||
RLIM_NPROC, as threads are procs on some systems.
|
||||
|
||||
* imap4.c: removed silliness of malloc()ing a buffer the size of
|
||||
the entire message every time we retrieve a message.
|
||||
|
||||
* xalloc.c, xalloc.h: consolidated memory allocation so everyone
|
||||
handles OOM the same way (for now, dump core).
|
||||
|
||||
* constants.h: various assumptions and limits, were in bench.h.
|
||||
|
||||
* events: added event-queue model to reduce thread requirements.
|
||||
Eventually, it would be nice for a consultant to be able to run
|
||||
this off a laptop to test a small- to medium-sized box. For
|
||||
now, at least, configuration remains the same. This doesn't
|
||||
work on NT. Oh, well.
|
||||
@@ -101,14 +101,14 @@ pkg-share-files:: mkpkgdirs
|
||||
(cd $(PKGDIR); [ ! -f cleanup ] || rm -f cleanup; ln -s mstone cleanup)
|
||||
(cd $(PKGDIR); [ ! -f checktime ] || rm -f checktime; ln -s mstone checktime)
|
||||
(cd $(PKGDIR); [ ! -f timesync ] || rm -f timesync; ln -s mstone timesync)
|
||||
-$(CP) nsarch bin/*.pl $(PKGDIR)/bin
|
||||
-$(CP) conf/*.wld conf/*.wld.in conf/*.html $(PKGDIR)/conf
|
||||
-$(CP) data/*.msg $(PKGDIR)/data
|
||||
-$(CP) doc/*.html doc/*.gif $(PKGDIR)/doc
|
||||
-$(CP) INSTALL $(PKGDIR)
|
||||
-$(CP) README $(PKGDIR)
|
||||
-$(CP) ChangeLog $(PKGDIR)
|
||||
-$(CP) LICENSE $(PKGDIR)
|
||||
$(CP) nsarch bin/*.pl $(PKGDIR)/bin
|
||||
$(CP) conf/*.wld conf/*.wld.in conf/*.html $(PKGDIR)/conf
|
||||
$(CP) data/*.msg $(PKGDIR)/data
|
||||
$(CP) doc/*.html doc/*.gif $(PKGDIR)/doc
|
||||
$(CP) INSTALL $(PKGDIR)
|
||||
$(CP) README $(PKGDIR)
|
||||
$(CP) ChangeLog $(PKGDIR)
|
||||
$(CP) LICENSE $(PKGDIR)
|
||||
|
||||
# split out OS specific file so that combined packaging possible (set PKGDIR)
|
||||
pkg-arch-files-gd:: $(PKGDIR)/gd $(OBJDIR)/gd/libgd.a
|
||||
|
||||
@@ -9,7 +9,8 @@ as Mailstone.
|
||||
A quick installation guide is available in INSTALL.
|
||||
|
||||
The full Mailstone 4.15 user manual is available at
|
||||
http://lxr.mozilla.org/mozilla/source/mstone/doc/MailStone.html
|
||||
http://developer.iplanet.com/docs/manuals/messaging.html
|
||||
|
||||
|
||||
Testing strategy
|
||||
----------------
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
Under the terms of the Mozilla Public License, Version 1.1, granted
|
||||
by Mozilla, Sendmail Inc. is contributing the following Source Code
|
||||
changes to the Mozilla mstone source repository.
|
||||
|
||||
Sendmail, Inc. is making available these source code modifications
|
||||
according to the Distribution Obligations as listed in section 3
|
||||
of the Mozilla Public License, Version 1.1
|
||||
|
||||
The changes provided herein are described in the included files:
|
||||
|
||||
README.Sendmail-mstone_changes.html
|
||||
ChangeLog-Sendmail
|
||||
|
||||
All modifications are derived, directly or indirectly, from the original
|
||||
code as provided by Mozilla.
|
||||
|
||||
@@ -1,419 +0,0 @@
|
||||
<html>
|
||||
<head><title>Sendmail, Inc. Mstone changes</title></head>
|
||||
<body>
|
||||
|
||||
<h3>Mstone modifications</h3>
|
||||
|
||||
<ol>
|
||||
<li><h4>Random Variable Parameters</h4>
|
||||
|
||||
In addition to taking on constant values, some parameters can now be
|
||||
sampled from probability distributions. These variables are:
|
||||
<ul>
|
||||
<li><code>startDelay</code>
|
||||
<li><code>idleTime</code>
|
||||
<li><code>blockTime</code>
|
||||
<li><code>loopDelay</code>
|
||||
<li><code>numRecips</code>
|
||||
<li><code>size</code>
|
||||
<li><code>headers</code>
|
||||
<li><code>mime</code>
|
||||
<li><code>leaveMailOnServer</code>
|
||||
<li><code>bandwidth</code>
|
||||
<li><code>latency</code>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The following distributions are currently implemented:
|
||||
<ul>
|
||||
<li>Uniform (~unif(a, b))
|
||||
<li>Normal (~normal(a, b))
|
||||
<li>Log-Normal (~lognormal(a, b))
|
||||
<li>Weibull (~weib(a, b, c))
|
||||
<li>Exponential (~exp(a))
|
||||
<li>Constant (~const(a))
|
||||
<li>Binomial (~binomial(a))
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Sampled values may also be constrained by a minimum and maximum value.
|
||||
This is particularly useful for e.g. the normal and lognormal
|
||||
distributions, though over-tight constraints will create a "lump" at
|
||||
the end of the generated distribution, and any constraints may change
|
||||
the distribution's characteristics (e.g. mean). To specify
|
||||
constraints, do the following:
|
||||
|
||||
<h5>getdist</h5>
|
||||
|
||||
<p>
|
||||
There is also a helper tool called "getdist" in the Sendmail mstone
|
||||
distribution. Building getdist:
|
||||
|
||||
<pre>
|
||||
file: mstone/src/idle.c
|
||||
# gcc -DTEST_PROB -Dxalloc=malloc -Dxfree=free -lm idle.c
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Rename the resulting binary to "getdist"
|
||||
|
||||
<p>
|
||||
<b>Using getdist</b>
|
||||
|
||||
<p>
|
||||
To run it interactively:
|
||||
|
||||
<ol>
|
||||
<li>Start up getdist</li>
|
||||
<li>Enter the distribution you want to see a sample and mean (ignore warning about 'gets()')</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
% getdist
|
||||
warning: this program uses gets(), which is unsafe.
|
||||
~lognormal(3,4.5)
|
||||
Samples:
|
||||
6.846493
|
||||
0.109578
|
||||
31.402784
|
||||
0.467486
|
||||
21.905714
|
||||
7.113645
|
||||
0.225102
|
||||
29.372181
|
||||
4.252427
|
||||
1.444493
|
||||
mean: 29.128932
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
It will only OUTPUT 10 samples as examples but the mean
|
||||
is calculated based on 2000 samples by default. You can specify
|
||||
the mean sample size on the command line by giving it a -n option:
|
||||
|
||||
<pre>
|
||||
% getdist -n 1000000
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This will calculate the mean based on a sample of 1000000 entries.
|
||||
|
||||
<p>
|
||||
The above data was calculated with 2M samples.
|
||||
|
||||
<p>
|
||||
<i>Known Problems</i><BR>
|
||||
It appears (anecdotally) that the first set of samples returned by
|
||||
getdist are inaccurate. After starting the getdist program interactively,
|
||||
it may appear necessary to ignore the first set of output, but that entering
|
||||
the distribution again will return a more accurate result.<BR>
|
||||
|
||||
<p>
|
||||
For example:
|
||||
|
||||
<pre>
|
||||
# getdist
|
||||
~lognormal(10,2)
|
||||
Samples:
|
||||
670043.575395
|
||||
48.842052
|
||||
54.039792
|
||||
0.460849
|
||||
2.152179
|
||||
32.534664
|
||||
6.163511
|
||||
42.827706
|
||||
27.806642
|
||||
4.966444
|
||||
mean: 364.747532
|
||||
var: 224352671.855287
|
||||
stddev: 14978.406853
|
||||
~lognormal(10,2)
|
||||
Samples:
|
||||
1.842800
|
||||
39.760727
|
||||
4.798239
|
||||
10.722216
|
||||
27.052030
|
||||
28.923926
|
||||
61.504273
|
||||
20.743583
|
||||
5.373420
|
||||
42.195531
|
||||
mean: 25.510130
|
||||
var: 2674.124997
|
||||
stddev: 51.711942
|
||||
</pre>
|
||||
|
||||
|
||||
<dl>
|
||||
<dt><code>~dist(...) : [min,]</code>
|
||||
<dd>force all sampled values to be >= <code>min</code>
|
||||
<dt><code>~dist(...) : [min,max]</code>
|
||||
<dd>force all sampled values X to be <code>min</code> <= X <= <code>max</code>.
|
||||
<dt><code>~dist(...) : [,max]</code>
|
||||
<dd>force values to be <= <code>max</code>
|
||||
</dl>
|
||||
|
||||
<li><h4>Parsing Changes</h4>
|
||||
|
||||
All of the time-valued test parameters except <code>rampTime</code>
|
||||
and <code>time</code> now have millisecond values. In particular,
|
||||
this means that a value of "17" parses to 17
|
||||
<strong>milliseconds</strong>, not 17 seconds. Use "17s" instead.
|
||||
<p>
|
||||
|
||||
Size-valued parameters can have units of "k" or "m" to indicate
|
||||
kilobytes or megabytes, respectively.
|
||||
<p>
|
||||
|
||||
For parameters supporting random-variable values, a value starting
|
||||
with "~" will be interpreted as a random variable specification of the
|
||||
form "~NAME([ARGS ...])". Unit suffixes (e.g. "s", and "m") apply to
|
||||
random variable parameters as well as constant values. This implies
|
||||
that for unitless parameters, the suffixes corresponding to the random
|
||||
variable's units will still be recognized (i.e. the values will be
|
||||
multiplied by the appropriate factors). This is probably best
|
||||
considered as a "bug" rather than excercised as a "feature."
|
||||
<p>
|
||||
|
||||
<code>blockTime</code>, <code>loopDelay</code>, and
|
||||
<code>idleTime</code> now refer to the total amount of time a command
|
||||
block, loop, and initialization phase should take, respectively, not
|
||||
the amount of time the simulation should stall after completing each
|
||||
phase. For example, if a block takes 2 seconds to complete, and the
|
||||
block time is 4 seconds, the client thread will sleep for 2 seconds
|
||||
after finishing instead of the full 4.<p>
|
||||
|
||||
<code>rampTime</code> is now solely for the benefit of the client
|
||||
machines, to control the rate at which threads are started. The rate
|
||||
at which commands from a given protocol are started is now controlled
|
||||
by the <code>startDelay</code> variable, which is
|
||||
distribution-valued. Thus the actual command loop now looks like
|
||||
this:
|
||||
|
||||
<pre>
|
||||
wait for startDelay
|
||||
start counting idleTime
|
||||
start counting blockTime
|
||||
execute start function
|
||||
wait for remainder of idleTime
|
||||
for (1 ... numLoops)
|
||||
start counting loopDelay
|
||||
execute loop function
|
||||
wait for remainder of loopDelay
|
||||
execute end function
|
||||
wait for remainder of blockTime
|
||||
</pre>
|
||||
|
||||
<li><h4>Automatic Message Generation</h4>
|
||||
|
||||
Both MIME and text/plain messages can now be generated automatically.
|
||||
To enable automatic message generation, set the <code>file</code>
|
||||
attribute of an SMTP block to "auto". The messages will then have at
|
||||
least as many headers as the value of the <code>headers</code>
|
||||
attribute, have bodies <code>size</code> bytes long, and have
|
||||
<code>mime</code> MIME parts. To generate text/plain messages, set
|
||||
<code>mime</code> to zero.
|
||||
|
||||
<table border=1 cellpadding=2>
|
||||
<tr><th>Attribute</th><th>Description</th></tr>
|
||||
|
||||
<tr>
|
||||
<td><code>headers <i>N</i></code></td>
|
||||
<td>(optional; default=5) Each automatically generated message will
|
||||
have <code>min(<i>N</i>, min_hdrs)</code> headers, where
|
||||
<code>min_hdrs</code> is 5 for text/plain, and about 7 for MIME
|
||||
messages. Additional headers are named
|
||||
"X-generated-header-%d". </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>size <i>N</i></code></td>
|
||||
<td>(required) Each generated message will have a body be <i>N</i>
|
||||
bytes long.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>mime <i>N</i></code></td>
|
||||
<td>Each generated message will have <code>N</code> MIME parts. If
|
||||
the value of <code>size</code> does not allow <code>N</code> parts,
|
||||
one part is generated. If <code>N</code> is zero, the message is
|
||||
text/plain.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>checksum <i>{yes|no|save}</i></code></td>
|
||||
<td>For SMTP: each generated message will have the MD5 sum of the
|
||||
message body appended to the message unless the value is <i>no</i>.
|
||||
For retrieval protocols, checksums will be verified. (NOT
|
||||
IMPLEMENTED: if <code>checksum</code> is <i>save</i>, messages with
|
||||
incorrect checksums will be saved to temporary files for later
|
||||
examination.) </td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<li><h4>Linespeed Emulation</h4>
|
||||
|
||||
SMTP, POP, and IMAP all support a form of linespeed emulation,
|
||||
controlled via the <code>latency</code> and <code>bandwidth</code>
|
||||
parameters.
|
||||
|
||||
<table border=1 cellpadding=2>
|
||||
<tr><th>Attribute</th><th>Description</th></tr>
|
||||
|
||||
<tr><td><code>latency <i>N</i></code></td>
|
||||
<td>Set the network latency to <code>N</code> milliseconds.</td></tr>
|
||||
|
||||
<tr><td><code>bandwidth <i>N</i></code></td>
|
||||
|
||||
<td>Transfer at most <code>N</code> bytes per second.</td></tr>
|
||||
|
||||
</table>
|
||||
|
||||
<li><h4>TLS support</h4>
|
||||
|
||||
If you have openssl, mstone now supports STARTTLS for SMTP and IMAP,
|
||||
and STLS for POP (both old-style and MULTIPOP), as well as SSL
|
||||
tunneling. This support is <strong>not</strong> well-tested, and TLS
|
||||
can be a bit tricky to set up, so use at your own risk. TLS
|
||||
introduces several new attributes to the protocol blocks:
|
||||
|
||||
<table border=1 cellpadding=2>
|
||||
<tr><th>Attribute</th><th>Description</th></tr>
|
||||
|
||||
<tr><td><code>sslcert <i>filename</i></code></td>
|
||||
<td>Read the client's cert from <i>filename</i>, which should be in
|
||||
PEM format. </td></tr>
|
||||
|
||||
<tr><td><code>sslkey <i>filename</i></code></td>
|
||||
|
||||
<td>Read the client's private key from <i>filename</i>, which should
|
||||
be in PEM format.</td></tr>
|
||||
|
||||
<tr><td><code>usetls {0|1}</code></td>
|
||||
|
||||
<td>Turn STARTTLS/STLS on or off (default: off). <b>Note</b>:
|
||||
<code>starttls</code> and <code>ssltunnel</code> are mutually
|
||||
exlcusive.</td></tr>
|
||||
|
||||
<tr><td><code>ssltunnel {0|1}</code></td>
|
||||
|
||||
<td>Turn SSL tunneling on or off (default: off).</td></tr>
|
||||
|
||||
</table>
|
||||
|
||||
<li><h4>"Multi-POP" protocol</h4>
|
||||
|
||||
<b>Note</b>: multipop, always a band-aid, is hopefully obsoleted by
|
||||
the new event-queue execution model. Though it has not been tested,
|
||||
it should be easier, more efficient, and more accurate to use the
|
||||
normal POP protocol with events to simulate a large number of users
|
||||
with a reasonable number of threads. Once this has been tested,
|
||||
automatically-generated workloads should revert to using POP.
|
||||
|
||||
<p>To simulate a large number of concurrently active POP users with
|
||||
Mstone's extravagant use of threads, and to simulate a period of
|
||||
activity comprised of several POP sessions one can use the MULTIPOP
|
||||
protocol to multiplex active users onto a single thread. The protocol
|
||||
has all the same parameters as POP, plus the following:
|
||||
|
||||
<table border=1 cellpadding=2>
|
||||
<tr><th>Attribute</th><th>Description</th></tr>
|
||||
|
||||
<tr><td><code>userSpacing</code></td>
|
||||
|
||||
<td>Total time for each user's session.</td>
|
||||
</tr>
|
||||
<tr><td><code>usersPerModem</code></td>
|
||||
|
||||
<td>The maximum number of concurrently connected users is limited
|
||||
to <code>users / usersPerModem</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
|
||||
The protocol functions are substantially different. Instead of
|
||||
simulating a single login-check-logout sequence, a protocol block
|
||||
simulates an entire active period for a set of users. Each user
|
||||
checks mail once in the initialization function, once each time the
|
||||
loop body is executed, and once more in the protocol conclusion
|
||||
function.
|
||||
<p>
|
||||
|
||||
<li><h4>"Event-queue" implementation</h4>
|
||||
|
||||
<p>
|
||||
Unless the "noevents" parameter in the "<config>" section is set to 1,
|
||||
or mailclient is not given the "-e" flag, mstone will run in
|
||||
"event-queue" mode. Instead of creating one thread per client, it
|
||||
will multiplex clients over a much smaller number of threads. This is
|
||||
intended to increase the tool's scalability.
|
||||
|
||||
<p>
|
||||
Note that I/O is still synchronous with this model, so the number of
|
||||
threads required will approximately equal the maximum number of
|
||||
concurrent operations. Also note that this change does not reduce the
|
||||
number of required file descriptors.
|
||||
|
||||
<p>
|
||||
|
||||
<li><h4>Other Minor Additions</h4>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>IMAP now has a ramp-down time, enabled by defining
|
||||
<code>IMAP_RAMPDOWN</code>. IMAP threads now exit uniformly between
|
||||
the time the test is supposed to be over and the time Mstone starts
|
||||
killing them.
|
||||
|
||||
<li>Mstone used to always time out connections after 60 seconds. The
|
||||
timeout value can now be configured on a per-block basis via the
|
||||
<code>timeout</code> parameter. The value of the timeout parameter must
|
||||
be defined in milliseconds, so the following value would mean a timeout
|
||||
of one (1) hour:<BR>
|
||||
|
||||
timeout 3600000
|
||||
|
||||
<li>Simplified client allocation. It is now possible to specify the
|
||||
number of clients in each group by specifying a value for
|
||||
<code>clients</code> in each <code><CLIENT></code> section and
|
||||
<em>not</em> specifying a global <code>clientCount</code> in the
|
||||
<code><CONFIG></code> section.
|
||||
|
||||
</ul>
|
||||
|
||||
<li><h4>Bug Fixes</h4>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>SMTP now ignores debugging output appearing over the connection.
|
||||
Before, Mstone would generate an error when talking to
|
||||
e.g. <code>sendmail -d64.5</code>.
|
||||
|
||||
<li>(now it works...) The old sequence of IMAP commands used by
|
||||
Mstone was incorrect. Instead of only downloading unread messages, it
|
||||
would download all messages received since the start of the session
|
||||
each time a new messages was received. Depending on what you were
|
||||
doing, this could have a serious effect on your results.
|
||||
|
||||
</ul>
|
||||
|
||||
<li><h4>Wish List</h4>
|
||||
|
||||
<ul>
|
||||
<li>Scriptable user behavior for POP and IMAP protocols. While we should
|
||||
probably not go overboard, adding more configuration options to Mstone
|
||||
is probably not the answer. There is already some support for more
|
||||
complex behaviors in the IMAP code -- we may or may not want to make
|
||||
use of it. More to the point, wider coverage of the IMAP
|
||||
protocol is vital to QA's use of the tool.
|
||||
</ul>
|
||||
|
||||
</ol>
|
||||
</body></html>
|
||||
@@ -37,10 +37,10 @@
|
||||
#$mailstoneURL =
|
||||
# "http://home.netscape.com/eng/server/messaging/4.1/mailston/stone.htm";
|
||||
#$mailstoneURL =
|
||||
# "http://lxr.mozilla.org/mozilla/source/mstone/doc/MailStone.html";
|
||||
# "http://developer.iplanet.com/docs/manuals/messaging.html";
|
||||
#$mailstoneURL =
|
||||
# "http://docs.iplanet.com/docs/manuals/messaging/nms415/mailstone/stone.htm"
|
||||
$mailstoneURL = "doc/MailStone.html";
|
||||
$mailstoneURL = "http:doc/MailStone.html";
|
||||
|
||||
# Subdirs for results (each under a timestamp dir). Should just hardwire.
|
||||
$tmpbase = "tmp";
|
||||
@@ -59,6 +59,794 @@ do 'protoconf.pl' || die "$@\n";
|
||||
|
||||
%includedFiles = (); # array of included files
|
||||
|
||||
do 'util.pl' || die "$@\n";
|
||||
# Utility functions
|
||||
# Create a unique hash array. Programming Perl, 2nd edition, p291 (p217?)
|
||||
package ArrayInstance;
|
||||
sub new {
|
||||
my $type = shift;
|
||||
my %params = @_;
|
||||
my $self = {};
|
||||
return bless $self, $type;
|
||||
}
|
||||
|
||||
package main;
|
||||
|
||||
# run a command in the background, return its PID
|
||||
# Uses fork: will not run on NT in perl 5.004
|
||||
# if the server is "localhost", ignore the rcmd part
|
||||
# if stdin, stdout, and/or stderr is set, redirect those for the sub process
|
||||
sub forkproc {
|
||||
my $rcmd = shift;
|
||||
my $server = shift;
|
||||
my $command = shift;
|
||||
my $stdin = shift;
|
||||
my $stdout = shift;
|
||||
my $stderr = shift;
|
||||
|
||||
if (my $pid = fork()) {
|
||||
return $pid; # parent
|
||||
}
|
||||
|
||||
# rest of this is in the child
|
||||
if ($stdin) { # redirect stdin if needed
|
||||
close (STDIN);
|
||||
open STDIN, "<$stdin"
|
||||
|| die "Couldn't open $stdin for input\n";
|
||||
}
|
||||
|
||||
if ($stdout) { # redirect stdout if needed
|
||||
close (STDOUT);
|
||||
open STDOUT, ">>$stdout"
|
||||
|| die "Couldn't open $stdout for output\n";
|
||||
}
|
||||
|
||||
if ($stderr) { # redirect stderr if needed
|
||||
close (STDERR);
|
||||
open STDERR, ">>$stderr"
|
||||
|| die "Couldn't open $stderr for output\n";
|
||||
}
|
||||
|
||||
if ($server =~ /^localhost$/i) {
|
||||
exec $command;
|
||||
die "Coundn't exec $command:$!\n";
|
||||
} else {
|
||||
exec split (/\s+/, $rcmd), $server, $command;
|
||||
die "Coundn't exec $rcmd $server $command:$!\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Relocate file to tmp directory (if it is in the results directory),
|
||||
# and put a ~ on the end of it.
|
||||
# ASSUMES tmp and results are on the same partition (on NT, same drive).
|
||||
# Usage: fileBackup (filename)
|
||||
sub fileBackup {
|
||||
my $filename = shift;
|
||||
my $bfile = $filename;
|
||||
|
||||
(-f $filename) || return 0; # file doent exist
|
||||
$bfile =~ s/$resultbase/$tmpbase/; # move to tmp
|
||||
$bfile .= "~"; # indicate that this is a backup
|
||||
(-f $bfile) && unlink ($bfile);
|
||||
#print "Backing up $filename to $bfile\n"; # DEBUG
|
||||
rename ($filename, $bfile) || unlink ($filename);
|
||||
}
|
||||
|
||||
# Insert text into a file after a tagline
|
||||
# fileInsertAfter (filename, tagstring, newtext)
|
||||
sub fileInsertAfter {
|
||||
my $filename = shift || die "fileInsertAfter: missing filename";
|
||||
my $tagline = shift || die "fileInsertAfter: missing tagline";
|
||||
my $newtext = shift || die "fileInsertAfter: missing text";
|
||||
my $foundit = 0;
|
||||
|
||||
open(OLD, "<$filename") ||
|
||||
open(OLD, "gunzip -c $filename |") ||
|
||||
die "fileInsertAfter: Could not open input $filename: $!";
|
||||
open(NEW, ">$filename+") ||
|
||||
die "fileInsertAfter: Could not open output $filename+: $!";
|
||||
|
||||
while (<OLD>) {
|
||||
print NEW $_; # copy (including tagline)
|
||||
|
||||
next unless (/$tagline/); # matched tagline
|
||||
|
||||
print NEW $newtext; # insert new text
|
||||
$foundit++;
|
||||
last; # only change first occurance
|
||||
}
|
||||
|
||||
if ($foundit) { # copy rest of file
|
||||
while (<OLD>) {
|
||||
print NEW $_;
|
||||
}
|
||||
}
|
||||
|
||||
close (OLD);
|
||||
close (NEW);
|
||||
if ($foundit) {
|
||||
fileBackup ($filename);
|
||||
rename ("$filename+", "$filename");
|
||||
#print "Updated $filename\n"; # DEBUG
|
||||
return $foundit;
|
||||
} else {
|
||||
($params{DEBUG}) && print "No change to $filename\n"; # DEBUG
|
||||
unlink ("$filename+");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Do text for text replacements in a file.
|
||||
# Perl wildcards are automatically quoted.
|
||||
# fileReplace (filename, matchPat, oldtext, newtext)
|
||||
sub fileReplaceText {
|
||||
my $filename = shift || die "fileReplaceText: missing filename";
|
||||
my $tagline = shift || die "fileReplaceText: missing tagline ($filename)";
|
||||
my $oldtext = shift;
|
||||
my $newtext = shift;
|
||||
my $foundit = 0;
|
||||
|
||||
return if ($newtext eq ""); # nothing to do
|
||||
return if ($oldtext eq ""); # nothing can be done
|
||||
|
||||
open(OLD, "<$filename") ||
|
||||
open(OLD, "gunzip -c $filename |") ||
|
||||
die "fileReplaceText: Could not open input $filename: $!";
|
||||
open(NEW, ">$filename+") ||
|
||||
die "fileReplaceText: Could not open output $filename+: $!";
|
||||
|
||||
$oldtext =~ s/([][{}*+?^.\/])/\\$1/g; # quote regex syntax
|
||||
|
||||
while (<OLD>) {
|
||||
if (/$tagline/i) { # matched tagline
|
||||
$foundit++;
|
||||
s/$oldtext/$newtext/; # do the replace
|
||||
}
|
||||
print NEW $_;
|
||||
}
|
||||
|
||||
close (OLD);
|
||||
close (NEW);
|
||||
if ($foundit) {
|
||||
fileBackup ($filename);
|
||||
rename ("$filename+", "$filename");
|
||||
#print "Updated $filename\n"; # DEBUG
|
||||
return $foundit;
|
||||
} else {
|
||||
($params{DEBUG}) && print "No change to $filename\n"; # DEBUG
|
||||
unlink ("$filename+");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# copy a file to a new name. Handles possible compression. OS independent.
|
||||
# fileCopy (filename, newname)
|
||||
sub fileCopy {
|
||||
my $filename = shift || die "fileReplaceText: missing filename";
|
||||
my $newname = shift || die "fileReplaceText: missing newname ($filename)";
|
||||
|
||||
open(OLD, "<$filename") ||
|
||||
open(OLD, "gunzip -c $filename |") ||
|
||||
die "fileReplaceText: Could not open input $filename: $!";
|
||||
open(NEW, ">$newname") ||
|
||||
die "fileReplaceText: Could not open output $newname: $!";
|
||||
|
||||
while (<OLD>) { # copy it
|
||||
print NEW $_;
|
||||
}
|
||||
|
||||
close (OLD);
|
||||
close (NEW);
|
||||
return 0;
|
||||
}
|
||||
|
||||
# display a file to STDOUT. Handles possible compression
|
||||
sub fileShow {
|
||||
my $filename = shift || die "fileShow: missing filename";
|
||||
open(SHOWIT, "<$filename") ||
|
||||
open(SHOWIT, "gunzip -c $filename.gz |") ||
|
||||
die "fileShow: Couldn't open $filename: $!";
|
||||
while (<SHOWIT>) { print; }
|
||||
close(SHOWIT);
|
||||
}
|
||||
|
||||
# sub function to figure time extents
|
||||
# (start, end) = dataMinMax counterName \@protocols oldstarttime oldendtime
|
||||
# Use 0 for uninitialized start or end
|
||||
sub dataMinMax {
|
||||
my $name = shift;
|
||||
my $protos = shift;
|
||||
my $start = shift;
|
||||
my $end = shift;
|
||||
|
||||
# make global
|
||||
# create the plot script and data files
|
||||
# Figure out the encompassing time extent
|
||||
foreach $p (@$protos) { # create the plot data files
|
||||
my @times = sort numeric keys %{ $graphs{$p}->{$name}};
|
||||
if ($#times <= 0) {
|
||||
next;
|
||||
}
|
||||
if (($start == 0) || ($times[0] < $start)) {
|
||||
$start = $times[0];
|
||||
}
|
||||
if (($end == 0) || ($times[0] > $end)) {
|
||||
$end = $times[$#times];
|
||||
}
|
||||
}
|
||||
#printf ("Data $name start=$start end=$end (%d points)...\n",
|
||||
# $end - $start);
|
||||
return ($start, $end);
|
||||
}
|
||||
|
||||
# simple function to formatted a number into n, n K, n M, or n G
|
||||
sub kformat {
|
||||
my $n = shift;
|
||||
my $r = "";
|
||||
if ($n > (1024*1024*1024)) {
|
||||
$r = sprintf "%.2fG", $n / (1024*1024*1024);
|
||||
} elsif ($n > (1024*1024)) {
|
||||
$r = sprintf "%.2fM", $n / (1024*1024);
|
||||
} elsif ($n > 1024) {
|
||||
$r = sprintf "%.2fK", $n / 1024;
|
||||
} else {
|
||||
$r = sprintf "%d ", $n;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
# simple function to formatted a time into Ns, Nms, or Nus
|
||||
# the goal is to make a table of timss uncluttered and easy to read
|
||||
# I dont convert to minutes or hours because the non-1000x multipliers
|
||||
# are hard to back solve in your head for comparisons
|
||||
sub tformat {
|
||||
my $n = shift;
|
||||
my $r = "";
|
||||
if ($n == 0.0) {
|
||||
$r = "0.0"; # make exactly 0 explicit
|
||||
} elsif ($n < 0.001) {
|
||||
$r = sprintf "%.2fus", $n * 1000 * 1000;
|
||||
} elsif ($n < 1.0) {
|
||||
$r = sprintf "%.2fms", $n * 1000;
|
||||
} elsif ($n >= 1000.0) {
|
||||
$r = sprintf "%.0fs", $n;
|
||||
} elsif ($n >= 100.0) {
|
||||
$r = sprintf "%.1fs", $n;
|
||||
} else {
|
||||
$r = sprintf "%.3fs", $n;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
#Usage: commify (1234567) returns 1,234,567
|
||||
sub commify { # perl cookbook p64-65
|
||||
my $text = reverse $_[0];
|
||||
$text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
|
||||
return scalar reverse $text;
|
||||
}
|
||||
|
||||
# subroutine to enable numeric sorts. Programming Perl p218
|
||||
# Use: sort numeric ...
|
||||
sub numeric { $a <=> $b; }
|
||||
|
||||
# on NT, turn slash to backslash, then print. Else print.
|
||||
sub pathprint {
|
||||
my $str = shift;
|
||||
$str =~ s!/!\\!g if ($params{NT}); # turn slash to back slash
|
||||
print $str;
|
||||
}
|
||||
|
||||
# figureTimeNumber number
|
||||
# Given an number like: 60m, 1h, 100s, 4d, 200
|
||||
# Return 60, 1, 100, 4, 200
|
||||
sub figureTimeNumber {
|
||||
my $arg = shift;
|
||||
|
||||
($arg =~ /([0-9]+)(s|sec|second|seconds|m|min|minute|minutes|h|hr|hour|hours|d|day|days)$/i)
|
||||
&& return $1;
|
||||
return $arg; # return default
|
||||
}
|
||||
|
||||
# figureTimeUnits number, default
|
||||
# Given an number like: 60m, 1h, 100s, 4d
|
||||
# Return a string of minutes, hours, seconds, days
|
||||
# Else return the second argument
|
||||
sub figureTimeUnits {
|
||||
my $arg = shift;
|
||||
|
||||
($arg =~ /(s|sec|second|seconds)$/i) && return "seconds";
|
||||
($arg =~ /(m|min|minute|minutes)$/i) && return "minutes";
|
||||
($arg =~ /(h|hr|hour|hours)$/i) && return "hours";
|
||||
($arg =~ /(d|day|days)$/i) && return "days";
|
||||
|
||||
return shift; # return default
|
||||
}
|
||||
|
||||
# figureTimeSeconds number, defaultUnits
|
||||
# Given an number like: 60m, 2h, 100s, 4d
|
||||
# Return 60*60, 2*60*60, 100, 4*24*60*60
|
||||
sub figureTimeSeconds {
|
||||
my $arg = shift;
|
||||
|
||||
($arg =~ /([0-9]+)(s|sec|second|seconds)$/i) && return $1;
|
||||
($arg =~ /([0-9]+)(m|min|minute|minutes)$/i) && return (60*$1);
|
||||
($arg =~ /([0-9]+)(h|hr|hour|hours)$/i) && return (60*60*$1);
|
||||
($arg =~ /([0-9]+)(d|day|days)$/i) && return (24*60*60*$1);
|
||||
|
||||
if ($_) {
|
||||
my $def = shift;
|
||||
return $arg * figureTimeSeconds ("1$def"); # return scaled by default
|
||||
} else {
|
||||
return $arg; # return it
|
||||
}
|
||||
}
|
||||
|
||||
# BACK COMPATIBILITY (everything now in the workload file)
|
||||
# read the testbed conf file, convert to workload sections
|
||||
# machine, how many processes, how many threads/proc, arch
|
||||
# only the first 2 fields are required. Lines starting with # are ignored.
|
||||
# You can include other files using <include conf/filename.tbd>
|
||||
# exampe:
|
||||
# client1 5 10 SunOS5.5.1
|
||||
sub readTestbedFile {
|
||||
my $filename = shift;
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
print "Testbed $filename skipped, clients read in workload\n";
|
||||
return 1; # clients already read in workload
|
||||
}
|
||||
|
||||
my $level = 0;
|
||||
if ($_) {
|
||||
$level = 1 + shift;
|
||||
die "Too many nested includes ($level) in $filename!"
|
||||
unless ($level < 100);
|
||||
}
|
||||
my $handle = "$filename$level";
|
||||
open($handle, "<$filename") ||
|
||||
open($handle, "gunzip -c $filename.gz |") ||
|
||||
die "Couldn't open testbed $filename: $!";
|
||||
|
||||
while(<$handle>) {
|
||||
chomp;
|
||||
|
||||
s/#.*//; # strip any comments from line
|
||||
|
||||
m/^\s*$/o && next; # continue if blank line
|
||||
|
||||
# handle include statement
|
||||
if (m/^<(include|INCLUDE)\s+([^\s]+)\s*>/o) {
|
||||
#print "Including $2 from $filename\n";
|
||||
readTestbedFile ($2, $level) || die;
|
||||
next;
|
||||
}
|
||||
|
||||
# get the server name and number of processes
|
||||
my @line = split(/\s+/);
|
||||
# create CLIENT entry in workload
|
||||
my $sparm = ArrayInstance->new();
|
||||
if ($line[1]) {
|
||||
$sparm->{"sectionTitle"} = "CLIENT";
|
||||
$sparm->{"sectionParams"} = "HOSTS=$line[0]";
|
||||
$sparm->{"PROCESSES"} = $line[1];
|
||||
$sparm->{"THREADS"} = $line[2] if ($line[2]);
|
||||
$sparm->{"ARCH"} = $line[3] if ($line[3]);
|
||||
} else {
|
||||
$sparm->{"sectionTitle"} = "MONITOR";
|
||||
$sparm->{"sectionParams"} = "HOSTS=$line[0]";
|
||||
$sparm->{"COMMAND"} = $line[2];
|
||||
}
|
||||
($params{DEBUG})
|
||||
&& print "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
|
||||
push @workload, $sparm;
|
||||
}
|
||||
close ($handle);
|
||||
}
|
||||
|
||||
# BACK COMPATIBILITY (everything now in the saved workload file)
|
||||
# This is now only needed to process mailstone4.1 runs
|
||||
sub readConfigFile {
|
||||
my $filename = shift;
|
||||
open(CONFIG, "<$filename") ||
|
||||
open(CONFIG, "gunzip -c $filename.gz |") ||
|
||||
die "Couldn't open config file $filename: $!";
|
||||
|
||||
while(<CONFIG>) {
|
||||
chomp;
|
||||
|
||||
s/#.*//; # strip any comments from line
|
||||
|
||||
m/^\s*$/o && next; # continue if blank line
|
||||
|
||||
# get the property and value
|
||||
my @line = split(/=/);
|
||||
$params{$line[0]} = $line[1];
|
||||
}
|
||||
close CONFIG;
|
||||
}
|
||||
|
||||
# read the workload file and store it as a list of hashes
|
||||
# Each hash always has the fields: sectionTitle and sectionParams
|
||||
# usage: readWorkloadFile filename, \@list
|
||||
sub readWorkloadFile {
|
||||
my $filename = shift || die "readWorkloadFile: Missing file name";
|
||||
my $plist = shift || die "readWorkloadFile: Missing return list";
|
||||
my $level = 0; # file inclusion level
|
||||
my @handles;
|
||||
|
||||
my $fh = "$filename$level";
|
||||
|
||||
($params{DEBUG}) && print "Reading workload from $filename.\n";
|
||||
open($fh, "<$filename") ||
|
||||
open($fh, "gunzip -c $filename.gz |") ||
|
||||
die "readWorkloadFile Couldn't open testbed $filename: $!";
|
||||
$includedFiles{$filename} = 1; # mark file as included
|
||||
|
||||
my $sparm=0;
|
||||
my $conline = "";
|
||||
|
||||
while($fh) {
|
||||
while(<$fh>) {
|
||||
s/#.*//; # strip any comments from line (quoting?)
|
||||
s/\s*$//; # strip trailing white space
|
||||
if ($conline) { # utilize line continue
|
||||
$_ = $conline . "\\\n" . $_;
|
||||
$conline = "";
|
||||
}
|
||||
if (m/\\$/o) { # check for quoted line continue
|
||||
s/\\$//; #
|
||||
$conline = $_;
|
||||
next;
|
||||
}
|
||||
s/^\s*//; # strip initial white space
|
||||
m/^$/o && next; # continue if blank line
|
||||
|
||||
# handle include and includeOnce statements
|
||||
if ((m/^<(include)\s+(\S+)\s*>/i)
|
||||
|| (m/^<(includeonce)\s+(\S+)\s*>/i)) {
|
||||
my $incfile = $2;
|
||||
if (($1 =~ m/^includeonce/i) && ($includedFiles{$incfile})) {
|
||||
($params{DEBUG})
|
||||
&& print "readWorkloadFile:includeOnce $incfile already read.\n";
|
||||
next;
|
||||
}
|
||||
($params{DEBUG})
|
||||
&& print "readWorkloadFile include $incfile from $filename.\n";
|
||||
$includedFiles{$incfile} = 1; # mark file
|
||||
push @handles, $fh; # push current handle on to stack
|
||||
if ($level++ > 99) { # check recursion and make handles unique
|
||||
die "readWorkloadFile: include level too deep: $filename $level\n";
|
||||
}
|
||||
$fh = "$incfile$level";
|
||||
open($fh, "<$incfile") ||
|
||||
open($fh, "gunzip -c $incfile.gz |") ||
|
||||
die "readWorkloadFile Couldn't open testbed file $incfile: $!";
|
||||
$filename = $incfile; # for error messages
|
||||
next;
|
||||
}
|
||||
|
||||
if (m!^</(\w+)>$!o) { # end of section
|
||||
my $end = $1;
|
||||
unless ($sparm->{"sectionTitle"} =~ /$end/i) {
|
||||
die "readWorkloadFile Mismatched section $filename: $. '$sparm->{sectionTitle}' '$end'\n";
|
||||
return 0;
|
||||
}
|
||||
($params{DEBUG}) && print "</$sparm->{sectionTitle}>\n";
|
||||
push @$plist, $sparm;
|
||||
$sparm = 0;
|
||||
next;
|
||||
}
|
||||
|
||||
if (m!^<(\w+)\s*(.*)>$!o) { # start of section
|
||||
my $sec = $1;
|
||||
my $more = $2;
|
||||
|
||||
if ($sparm) {
|
||||
die "readWorkloadFile Missing section end $filename: $. '$sparm->{sectionTitle}'\n";
|
||||
}
|
||||
if ($sec =~ /CONFIG/i) { # special case, map to existing global
|
||||
$sparm = \%params;
|
||||
} elsif ($sec =~ /DEFAULT/i) { # special case, only one DEFAULT
|
||||
if ($defaultSection) { # use existing defaultSection
|
||||
$sparm = $defaultSection;
|
||||
} else { # create a new one
|
||||
$sparm = ArrayInstance->new();
|
||||
$sparm->{"sectionTitle"} = uc $sec; # ignore case
|
||||
$sparm->{"lineList"} = ();
|
||||
$defaultSection = $sparm;
|
||||
}
|
||||
} else {
|
||||
$sparm = ArrayInstance->new();
|
||||
$sparm->{"sectionTitle"} = uc $sec; # ignore case
|
||||
$sparm->{"lineList"} = ();
|
||||
}
|
||||
$sparm->{"sectionParams"} = $more; # take newest more info
|
||||
($params{DEBUG})
|
||||
&& print "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
|
||||
next;
|
||||
}
|
||||
|
||||
# must be in a section, get parameters
|
||||
unless ($sparm) {
|
||||
die "readWorkloadFile Entry encountered outside a section $filename: $. $_\n";
|
||||
return 0;
|
||||
}
|
||||
my ($nm, $val) = split (/[\s=]+/, $_, 2);
|
||||
$nm = uc $nm; # ignore case
|
||||
($params{DEBUG}) && print " $nm = $val\n";
|
||||
if ($nm =~ /ACCOUNTFORMAT/) { # BACK COMPATIBILITY
|
||||
print "WARNING: 'accountFormat' is obsolete. Use 'addressFormat' and 'loginFormat'\n";
|
||||
$sparm->{"addressFormat"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "addressFormat $val";
|
||||
$val =~ s/@.+$//; # strip at and everything after
|
||||
$sparm->{"loginFormat"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "loginFormat $val";
|
||||
next;
|
||||
} elsif ($nm =~ /NUMACCOUNTS/) { # BACK COMPATIBILITY
|
||||
print "WARNING: 'numAccounts' is obsolete. Use 'numAddresses' and 'numLogins'\n";
|
||||
$sparm->{"numAddresses"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "numAddresses $val";
|
||||
$sparm->{"numLogins"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "numLogins $val";
|
||||
next;
|
||||
} elsif ($nm =~ /BEGINACCOUNTS/) { # BACK COMPATIBILITY
|
||||
print "WARNING: 'beginAccounts' is obsolete. Use 'firstAddress' and 'firstLogin'\n";
|
||||
$sparm->{"firstAddress"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "firstAddress $val";
|
||||
$sparm->{"firstLogin"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "firstLogin $val";
|
||||
next;
|
||||
}
|
||||
push @{$sparm->{"lineList"}}, $_; # save lines in original order
|
||||
$sparm->{$nm} = $val;
|
||||
next;
|
||||
}
|
||||
close ($fh);
|
||||
$fh = pop @handles || last; # empty include stack
|
||||
$filename = $fh;
|
||||
$sparm = 0; # can only include whole sections
|
||||
}
|
||||
return 1; # success
|
||||
}
|
||||
|
||||
# Write out a workload list to a file
|
||||
# Optionally, pass in a list of sectionTitle's it should ignore
|
||||
# usage: writeWorkloadFile filename \@list [\@skipList]
|
||||
sub writeWorkloadFile {
|
||||
my $filename = shift || die "writeWorkloadFile: Missing file name";
|
||||
my $plist = shift || die "writeWorkloadFile: Missing return list";
|
||||
my $skip = shift;
|
||||
my @skipH;
|
||||
my $configSeen = 0;
|
||||
my $defaultSeen = 0;
|
||||
my @paramH;
|
||||
|
||||
if ($skip) {
|
||||
foreach $s (@$skip) { # turn list into a hash
|
||||
$skipH{(uc $s)} = $s; # fix case for index
|
||||
}
|
||||
}
|
||||
foreach $s (@workloadParameters) { # turn list into a hash
|
||||
$paramH{(uc $s)} = $s; # fix case for index
|
||||
}
|
||||
|
||||
($params{DEBUG}) && print "Writing workload to $filename.\n";
|
||||
unless (open(WORKOUT, ">$filename")) {
|
||||
die "Couldn't open testbed $filename: $!";
|
||||
}
|
||||
|
||||
foreach $sparm (@$plist) { # each hash reference in the list
|
||||
if (($skip)
|
||||
&& ($skipH{$sparm->{"sectionTitle"}})) {
|
||||
#($params{DEBUG}) &&
|
||||
#print "Skipping section $sparm->{sectionTitle}\n";
|
||||
next;
|
||||
}
|
||||
|
||||
# all CONFIG,DEFAULT sections point to the same hash, output once only
|
||||
if ($sparm->{"sectionTitle"} =~ /^CONFIG$/) {
|
||||
next if $configSeen;
|
||||
$configSeen++;
|
||||
}
|
||||
if ($sparm->{"sectionTitle"} =~ /^DEFAULT$/) {
|
||||
next if $defaultSeen;
|
||||
$defaultSeen++;
|
||||
}
|
||||
if ($sparm->{sectionParams}) { # write section with extra args
|
||||
print WORKOUT "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
|
||||
} else {
|
||||
print WORKOUT "<$sparm->{sectionTitle}>\n";
|
||||
}
|
||||
if ($sparm->{"sectionTitle"} =~ /^(CONFIG|CLIENT)$/) {
|
||||
# for Config or Client, output the hash to get computed config
|
||||
foreach $k (sort keys %$sparm) { # output each parameter
|
||||
# skip sectionTitle and sectionParams
|
||||
($k =~ /^(sectionTitle|sectionParams|lineList)$/) && next;
|
||||
printf WORKOUT " %s\t%s\n",
|
||||
($paramH{$k}) ? $paramH{$k} : $k,
|
||||
$sparm->{$k};
|
||||
}
|
||||
} else { # write out the line list
|
||||
foreach $l (@{$sparm->{"lineList"}}) {
|
||||
print WORKOUT " $l\n";
|
||||
}
|
||||
}
|
||||
print WORKOUT "</$sparm->{sectionTitle}>\n\n";
|
||||
}
|
||||
close WORKOUT;
|
||||
}
|
||||
|
||||
# Usage: getClientFilename hostname section
|
||||
sub getClientFilename {
|
||||
my $cli = shift || die "Missing client name";
|
||||
my $section = shift || die "Missing section hash";
|
||||
return "$tmpdir/$cli-$section->{GROUP}.out"
|
||||
if ($params{USEGROUPS} && $section->{GROUP});
|
||||
return "$tmpdir/$cli.out"
|
||||
}
|
||||
|
||||
sub setConfigDefaults { # set CONFIG defaults
|
||||
# These are set after writing out the test copy to avoid clutter
|
||||
|
||||
# Path to gnuplot executable
|
||||
$params{GNUPLOT}="gnuplot/gnuplot"
|
||||
unless ($params{GNUPLOT});
|
||||
|
||||
# This is the directory the client lives in
|
||||
$params{TEMPDIR} = "/var/tmp"
|
||||
unless($params{TEMPDIR});
|
||||
|
||||
# Set default remote shell
|
||||
#$params{RSH} = "/usr/bin/rsh"
|
||||
$params{RSH} = "ssh"
|
||||
unless($params{RSH});
|
||||
|
||||
# Set default remote copy
|
||||
#$params{RCP} = "/usr/bin/rcp"
|
||||
$params{RCP} = "scp"
|
||||
unless($params{RCP});
|
||||
|
||||
# Size of generated gifs
|
||||
$params{CHARTHEIGHT} = 480
|
||||
unless($params{CHARTHEIGHT});
|
||||
$params{CHARTWIDTH} = 640
|
||||
unless($params{CHARTWIDTH});
|
||||
$params{CHARTPOINTS} = int (($params{CHARTWIDTH}-60)*0.8)
|
||||
unless($params{CHARTPOINTS});
|
||||
|
||||
|
||||
# The name of the remote executable
|
||||
$params{CLIENTCOMMAND} = "mailclient"
|
||||
unless ($params{CLIENTCOMMAND});
|
||||
|
||||
# Set default monitoring command
|
||||
$params{MONITORCOMMAND} = "vmstat %f"
|
||||
unless($params{MONITORCOMMAND});
|
||||
|
||||
# Set default switches to makeusers
|
||||
$params{MAKEUSERSARGS} = "-4"
|
||||
unless ($params{MAKEUSERSARGS});
|
||||
|
||||
# Figure out @protocols, this sets the report order
|
||||
@protocols = ();
|
||||
{
|
||||
my %skipH;
|
||||
foreach $s (@nonProtocolSections) { # turn list into a hash
|
||||
#print "$s ";
|
||||
$skipH{(uc $s)} = $s; # fix case for index
|
||||
}
|
||||
print "\n";
|
||||
foreach $sparm (@workload) { # each hash reference in the list
|
||||
next if ($skipH{$sparm->{"sectionTitle"}});
|
||||
|
||||
($params{DEBUG}) &&
|
||||
print "Found protocol ". $sparm->{"sectionTitle"} . "\n";
|
||||
|
||||
push @protocols, $sparm->{"sectionTitle"};
|
||||
# add to skip list so only added once
|
||||
$skipH{(uc $sparm->{"sectionTitle"})} = $sparm->{"sectionTitle"};
|
||||
}
|
||||
}
|
||||
@protocolsAll = @protocols;
|
||||
push @protocolsAll, "Total";
|
||||
|
||||
# figure out the graphs ???
|
||||
}
|
||||
|
||||
sub parseArgs { # get args
|
||||
while (@ARGV) {
|
||||
my $arg = shift(@ARGV);
|
||||
|
||||
if ($arg =~ /^-a$/i) { # was undocumented feature in 4.1
|
||||
$params{ADDGRAPHS} = shift(@ARGV); # extra graphs
|
||||
next;
|
||||
}
|
||||
if ($arg =~ /^-b$/i) {
|
||||
$params{TITLE} = shift(@ARGV); # banner
|
||||
next;
|
||||
}
|
||||
|
||||
# BACK COMPATIBILITY (everything now in the saved workload file)
|
||||
if ($arg =~ /^-c$/i) { # config file, read when encountered
|
||||
my $configFile = shift(@ARGV);
|
||||
readConfigFile ($configFile);
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-d$/i) {
|
||||
$params{DEBUG}++; # Debug
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-h$/i) { # Help
|
||||
print "Usage: -w workfile [-t time] [-r ramptime] [-l load] [-v] [-d]\n";
|
||||
print "\t[-b banner] [-n notes] [-s sysconfigfile] [-a add_graphs_file]\n";
|
||||
print "\t[-c configfile] [-m machinefile] [-z] [PARAM=value]...\n";
|
||||
|
||||
die "Usage";
|
||||
}
|
||||
|
||||
if ($arg =~ /^-l$/i) { # "load", FIX: naming conventions
|
||||
$params{CLIENTCOUNT} = shift(@ARGV); # desired client count
|
||||
next;
|
||||
}
|
||||
|
||||
# BACK COMPATIBILITY (everything now in the saved workload file)
|
||||
if ($arg =~ /^-m$/i) {
|
||||
$params{TESTBED} = shift(@ARGV); # testbed machines file
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-n$/i) {
|
||||
$params{COMMENTS} = shift(@ARGV); # notes
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-r$/i) {
|
||||
$params{RAMPTIME} = shift(@ARGV); # ramptime
|
||||
next;
|
||||
}
|
||||
if ($arg =~ /^-s$/i) {
|
||||
$params{SYSCONFIG} = shift(@ARGV); # system config html file
|
||||
next;
|
||||
}
|
||||
if ($arg =~ /^-t$/i) {
|
||||
$params{TIME} = shift(@ARGV); # test time
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-v$/i) {
|
||||
$params{VERBOSE} = 1; # verbose mode
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-w$/i) { # workload file (may occur multiple times)
|
||||
my $f = shift(@ARGV);
|
||||
readWorkloadFile ($f, \@workload) || die "Error reading workload: $@\n";
|
||||
$params{WORKLOAD} = $f;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-z$/i) {
|
||||
$params{NT} = 1; # NT mode
|
||||
next;
|
||||
}
|
||||
|
||||
# any other CONFIG parameter: FIELD=value
|
||||
if ($arg =~ /^(\w+)=(\S.*)$/) {
|
||||
my $field = uc $1;
|
||||
$params{$field} = $2;
|
||||
next;
|
||||
}
|
||||
die "Unknown argument '$arg'";
|
||||
}
|
||||
|
||||
if ($params{NT}) { # should use Cwd module
|
||||
$cwd = `cd`; # NT get current directory
|
||||
$cwd = `pwd` unless ($cwd); # in case we are really on UNIX
|
||||
} else {
|
||||
$cwd = `pwd`; # in case we are really on UNIX
|
||||
}
|
||||
chomp $cwd; # strip NL
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#
|
||||
# Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
# Marcel DePaolis <marcel@netcape.com>
|
||||
# Sean O'Rourke <sean@sendmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU Public License (the "GPL"), in which case the
|
||||
@@ -35,10 +34,6 @@
|
||||
# This file deals with the graphs data only
|
||||
# Interfaces to gnuplot to generate gifs for HTML inclusion.
|
||||
|
||||
do 'util.pl';
|
||||
sub warn_system;
|
||||
sub die_system;
|
||||
|
||||
# Type of images to hold plots (e.g. png, gif, jpeg, svg, tiff, pbm, etc)
|
||||
unless ($params{IMAGETYPE}) {
|
||||
# Should probe gnuplot and see if it can generate one of:
|
||||
@@ -51,11 +46,28 @@ unless ($params{IMAGETYPE}) {
|
||||
($params{DEBUG}) &&
|
||||
print "Asking gnuplot what output types it supports\n";
|
||||
|
||||
# SEAN: this appears to do what they want:
|
||||
warn_system "echo 'set term' | $params{GNUPLOT} > $outfile";
|
||||
my $infile = "$tmpbase/setterm.gpt";
|
||||
open (NEW, ">$infile") ||
|
||||
die "genPlot: Could not open output $infile: $!";
|
||||
print NEW "set terminal";
|
||||
close (NEW);
|
||||
# Redirect STDIN, and STDERR
|
||||
open SAVEIN, "<STDIN";
|
||||
open STDIN, "<$infile"
|
||||
|| die "Coundn't open $infile for input\n";
|
||||
open SAVEERR, ">&STDERR";
|
||||
open STDERR, ">$outfile"
|
||||
|| die "Couldnt open $outfile for output\n";
|
||||
system $params{GNUPLOT}; # gnuplot < $infile 2> $outfile
|
||||
# Restore STDERR and STDIN
|
||||
close STDERR;
|
||||
open STDERR, ">&SAVEERR";
|
||||
open STDIN, "<SAVEIN";
|
||||
|
||||
open(NEW, "<$outfile") ||
|
||||
warn ": Could not open gnuplot output for parsing ($outfile): $!";
|
||||
die ": Could not open gnuplot output for parsing ($outfile): $!";
|
||||
|
||||
unlink ($infile); # clean up
|
||||
}
|
||||
|
||||
# now check through the output for terminal types we can use.
|
||||
@@ -85,8 +97,7 @@ unless ($params{IMAGETYPE}) {
|
||||
elsif ($types{"tiff"}) { $params{IMAGETYPE}="tiff"; }
|
||||
elsif ($types{"pbm"}) { $params{IMAGETYPE}="pbm"; }
|
||||
else {
|
||||
warn "Gnuplot doesn't support any good image types. Check $outfile.\n";
|
||||
$params{IMAGETYPE} = undef;
|
||||
die "Gnuplot doesn't support any good image types. Check $outfile.\n";
|
||||
}
|
||||
# leave the output file around to speed up repeat runs
|
||||
}
|
||||
@@ -244,9 +255,6 @@ sub genPlot {
|
||||
close (DATA);
|
||||
}
|
||||
|
||||
# SEAN: don't even try if we aren't generating images:
|
||||
return 0 unless $params{IMAGETYPE};
|
||||
|
||||
# Create a script to feed to gnuplot, which creates a .gif graph.
|
||||
$runTime = ($endTime - $startTime + 1) * $timeStep;
|
||||
unlink("$tmpdir/$name.gpt");
|
||||
@@ -254,7 +262,6 @@ sub genPlot {
|
||||
|| die "Can't open $tmpdir/$name.gpt:$!";
|
||||
|
||||
$gnuplot = $params{GNUPLOT};
|
||||
return 1 unless $gnuplot;
|
||||
if ($gnuplot !~ /^\//) { # if not absolute, adjust for cd $tmpbase
|
||||
$gnuplot = "../../$gnuplot"; # ASSUME $tmpbase is single dir
|
||||
}
|
||||
@@ -292,7 +299,7 @@ plot [0:$runTime] $runlist
|
||||
# run script from tmpbase to clean up line labeling
|
||||
# my $olddir=getcwd();
|
||||
chdir $tmpdir;
|
||||
warn_system (split (/\s/, $gnuplot), "$name.gpt");
|
||||
system (split (/\s/, $gnuplot), "$name.gpt");
|
||||
chdir "../..";
|
||||
# chdir $olddir;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env perl
|
||||
#!/usr/bin/perl
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
@@ -49,9 +49,6 @@ print "Copyright (c) Netscape Communications Corp. 1997-2000\n";
|
||||
|
||||
# this parses the command line and config file
|
||||
do 'args.pl'|| die "$@\n";
|
||||
sub die_system;
|
||||
sub warn_system;
|
||||
|
||||
parseArgs(); # parse command line
|
||||
|
||||
{ # get unique date string
|
||||
@@ -156,7 +153,7 @@ if ($params{CLIENTCOUNT}) {
|
||||
my $softcli = 0; # how many can we play with
|
||||
|
||||
foreach $section (@workload) { # see which are already fixed
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
unless (($section->{PROCESSES}) && ($section->{THREADS})) {
|
||||
$softcli++;
|
||||
next;
|
||||
@@ -178,7 +175,7 @@ if ($params{CLIENTCOUNT}) {
|
||||
print "Allocating $todo clients over $softcli groups\n";
|
||||
if ($softcli) {
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
next if (($section->{PROCESSES}) && ($section->{THREADS}));
|
||||
my $slist = $section->{sectionParams};
|
||||
$slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
@@ -202,41 +199,18 @@ if ($params{CLIENTCOUNT}) {
|
||||
} else { # figure out the client count
|
||||
my $cnt = 0;
|
||||
foreach $section (@workload) { # see which are already fixed
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
# next unless ($section->{PROCESSES});
|
||||
next unless $section->{CLIENTS};
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
next unless ($section->{PROCESSES});
|
||||
|
||||
my $clients = $section->{CLIENTS};
|
||||
my $slist = $section->{sectionParams};
|
||||
$slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
my @hlist = split /[\s,]/, $slist;
|
||||
my $hcnt = scalar @hlist;
|
||||
|
||||
$clients /= $hcnt;
|
||||
my $maxp = ($section->{MAXPROCESSES} || 10000);
|
||||
my $maxt = ($section->{MAXTHREADS} || 10000);
|
||||
if ($maxp * $maxt < $clients) {
|
||||
die <<EOS;
|
||||
Too many clients for hosts $section->{sectionParams}:
|
||||
clients = $section->{CLIENTS}
|
||||
maxThreads = $section->{MAXTHREADS}
|
||||
maxProcesses = $section->{MAXPROCESSES}
|
||||
EOS
|
||||
}
|
||||
my ($nt, $np);
|
||||
if ($maxt >= $clients) {
|
||||
$nt = $clients;
|
||||
$np = 1;
|
||||
} else {
|
||||
$np = int (($clients / $maxt) + (($clients % $maxt) ? 1 : 0));
|
||||
$nt = int ($clients / $np);
|
||||
}
|
||||
my $hcnt = (1 + $#hlist);
|
||||
|
||||
$section->{THREADS} = $nt;
|
||||
$section->{PROCESSES} = $np;
|
||||
# $section->{CLIENTS} = $np * $nt * $hcnt;
|
||||
$cnt += $nt * $np * $hcnt;
|
||||
$clientProcCount += $np * $hcnt; # total processes
|
||||
# subtract fixed entries
|
||||
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 1;
|
||||
$cnt += $tcount * $section->{PROCESSES} * $hcnt;
|
||||
$clientProcCount += $section->{PROCESSES} * $hcnt; # total processes
|
||||
}
|
||||
$params{CLIENTCOUNT} = $cnt;
|
||||
die "No clients configured!\n" unless ($cnt > 0);
|
||||
@@ -284,17 +258,6 @@ writeWorkloadFile ("$resultdir/work.wld", \@workload,
|
||||
# Write the complete inclusive version
|
||||
writeWorkloadFile ("$resultdir/all.wld", \@workload);
|
||||
|
||||
# SEAN: copy the wld.in file to the result directory for later
|
||||
# statistics gathering.
|
||||
my $wld = $params{WORKLOAD};
|
||||
if (-f "$wld.in") {
|
||||
die_system "cp $wld.in $resultdir/wld.in";
|
||||
} else {
|
||||
unless ($wld !~ /\.preload_(new|old|touch)$/) {
|
||||
warn "Can't find wld.in file for `$wld'\n" unless -f "$wld.in";
|
||||
}
|
||||
}
|
||||
|
||||
setConfigDefaults(); # pick up any missing defaults
|
||||
|
||||
unless ($#protocolsAll > 0) {
|
||||
@@ -314,7 +277,7 @@ if ($params{NT}) { # single client on local host
|
||||
pathprint ("Starting clients (errors logged to $resultdir/stderr)\n");
|
||||
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 1;
|
||||
|
||||
|
||||
@@ -354,7 +317,7 @@ if ($params{NT}) { # single client on local host
|
||||
|| die "Couldnt open $stdout for output\n";
|
||||
|
||||
chdir $params{TEMPDIR} || die "Could not cd $params{TEMPDIR}: $!\n";
|
||||
warn_system $preCmd;
|
||||
system $preCmd;
|
||||
close STDOUT;
|
||||
open STDOUT, ">&SAVEOUT";
|
||||
printf "Test done.\n";
|
||||
@@ -365,7 +328,7 @@ if ($params{NT}) { # single client on local host
|
||||
} else { # not NT (forking works)
|
||||
|
||||
foreach $section (@workload) { # do pre run commands
|
||||
next unless ($section->{sectionTitle} =~ /PRETEST/i);
|
||||
next unless ($section->{sectionTitle} =~ /PRETEST/o);
|
||||
unless ($section->{COMMAND}) {
|
||||
print "PreTest with no Command for $section->{sectionParams}\n";
|
||||
next;
|
||||
@@ -398,7 +361,7 @@ if ($params{NT}) { # single client on local host
|
||||
}
|
||||
|
||||
foreach $section (@workload) { # start monitors
|
||||
next unless ($section->{sectionTitle} =~ /MONITOR/i);
|
||||
next unless ($section->{sectionTitle} =~ /MONITOR/o);
|
||||
|
||||
my $slist = $section->{sectionParams};
|
||||
$slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
@@ -432,7 +395,7 @@ if ($params{NT}) { # single client on local host
|
||||
|
||||
print "Starting clients (errors logged to $resultdir/stderr)\n";
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
next unless ($section->{PROCESSES}); # unused client
|
||||
|
||||
my $slist = $section->{sectionParams};
|
||||
@@ -448,7 +411,6 @@ if ($params{NT}) { # single client on local host
|
||||
}
|
||||
my $preCmd = "./" . (($section->{COMMAND})
|
||||
? $section->{COMMAND} : $params{CLIENTCOMMAND});
|
||||
$preCmd .= " -e" unless ($params{NOEVENTS});
|
||||
$preCmd .= " -s -t $params{TIME} -f $params{FREQUENCY}";
|
||||
$preCmd .= " -d" if ($params{DEBUG});
|
||||
$preCmd .= " -r" if ($params{TELEMETRY});
|
||||
@@ -468,38 +430,23 @@ if ($params{NT}) { # single client on local host
|
||||
$preCmd .= " -M $n";
|
||||
}
|
||||
$preCmd = "cd $tempdir; " . $preCmd if ($tempdir);
|
||||
$preCmd .= " -n $pcount";
|
||||
$preCmd =~ s!/!\\!g if ($section->{ARCH} eq "NT4.0");
|
||||
$preCmd =~ s/;/&&/g if ($section->{ARCH} eq "NT4.0");
|
||||
|
||||
my $total_clients = $section->{CLIENTS};
|
||||
my $residue = $total_clients - ($tcount * $pcount);
|
||||
foreach $cli (split /[\s,]/, $slist) {
|
||||
my $stdout = getClientFilename ($cli, $section);
|
||||
my $myCmd = $preCmd;
|
||||
$myCmd .= ($params{USEGROUPS} && $section->{GROUP})
|
||||
? " -H $section->{GROUP}" : " -H $cli";
|
||||
my $foo = ($params{USEGROUPS} && $section->{GROUP})
|
||||
? $section->{GROUP} : undef;
|
||||
|
||||
if ($tcount) {
|
||||
my $nt = $tcount;
|
||||
if ($residue > 0) {
|
||||
++$nt;
|
||||
$residue -= $pcount;
|
||||
}
|
||||
$myCmd .= " -n $pcount -N $nt";
|
||||
printf "Starting $pcount x $nt on $cli%s\n",
|
||||
$foo?" (group = $foo)":'';
|
||||
$totalProcs += $pcount * $nt;
|
||||
$myCmd .= " -N $tcount";
|
||||
printf "Starting %d x %d on $cli\n", $pcount, $tcount;
|
||||
$totalProcs += $pcount * $tcount;
|
||||
} else {
|
||||
my $np = $pcount;
|
||||
if ($residue > 0) {
|
||||
++$np;
|
||||
--$residue;
|
||||
}
|
||||
$myCmd .= " -n $np";
|
||||
printf "Starting $np processes on $foo\n";
|
||||
$totalProcs += $np;
|
||||
printf "Starting %d processes on $cli\n", $pcount;
|
||||
$totalProcs += $pcount;
|
||||
}
|
||||
|
||||
print STDERR "$cli: $myCmd\n"; # log the actual command
|
||||
@@ -538,7 +485,7 @@ if ($params{NT}) { # single client on local host
|
||||
}
|
||||
|
||||
foreach $section (@workload) { # do post test commands
|
||||
next unless ($section->{sectionTitle} =~ /POSTTEST/i);
|
||||
next unless ($section->{sectionTitle} =~ /POSTTEST/o);
|
||||
unless ($section->{COMMAND}) {
|
||||
print "PostTest with no command for $section->{sectionParams}\n";
|
||||
next;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env perl
|
||||
#!/usr/bin/perl
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
@@ -73,7 +73,7 @@ MailStone Results
|
||||
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#FF0000" ALINK="#000088">
|
||||
<A HREF=$mailstoneURL>Mailstone documentation</A><BR>
|
||||
<TABLE BORDER=2>
|
||||
<CAPTION> Mozilla MailStone Results Index </CAPTION>
|
||||
<CAPTION> Netscape MailStone Results Index </CAPTION>
|
||||
<TR>
|
||||
<TH>Run</TH> <TH>Testname</TH> <TH> Title </TH>
|
||||
<TH>Duration</TH> <TH>Clients</TH> <TH>Details</TH> <TH>Error log</TH>
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
#!/bin/sh
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Netscape Mailstone utility,
|
||||
# released March 17, 2000.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
# Marcel DePaolis <marcel@netcape.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU Public License (the "GPL"), in which case the
|
||||
# provisions of the GPL are applicable instead of those above.
|
||||
# If you wish to allow use of your version of this file only
|
||||
# under the terms of the GPL and not to allow others to use your
|
||||
# version of this file under the NPL, indicate your decision by
|
||||
# deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this
|
||||
# file under either the NPL or the GPL.
|
||||
#####################################################
|
||||
|
||||
# Figure out standard system names
|
||||
|
||||
UNAME_REPORTS=`uname`
|
||||
UNAME_OS_ARCH=`uname -s`
|
||||
UNAME_OS_RELEASE=`uname -r`
|
||||
|
||||
OS_ARCH=$UNAME_OS_ARCH
|
||||
OS_RELEASE=$UNAME_OS_RELEASE
|
||||
OS_CONFIG=${OS_ARCH}${OS_RELEASE}
|
||||
|
||||
if [ "$UNAME_OS_ARCH" = "SunOS" ]; then
|
||||
PROCESSOR=`uname -p`
|
||||
if [ "$PROCESSOR" = "i386" ]; then
|
||||
BUILD_ARCH=x86
|
||||
else
|
||||
BUILD_ARCH=SPARC
|
||||
fi
|
||||
BUILD_OS=SOLARIS
|
||||
if [ "$UNAME_OS_RELEASE" = "5.5" ]; then
|
||||
BUILD_VER=2.5
|
||||
elif [ "$UNAME_OS_RELEASE" = "5.5.1" ]; then
|
||||
BUILD_VER=2.5
|
||||
elif [ "$UNAME_OS_RELEASE" = "5.6" ]; then
|
||||
BUILD_VER=2.6
|
||||
elif [ "$UNAME_OS_RELEASE" = "5.7" ]; then
|
||||
BUILD_VER=7
|
||||
elif [ "$UNAME_OS_RELEASE" = "5.8" ]; then
|
||||
BUILD_VER=8
|
||||
fi
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "HP-UX" ]; then
|
||||
BUILD_ARCH=HPPA
|
||||
BUILD_OS=$UNAME_OS_ARCH
|
||||
BUILD_VER=$OS_RELEASE
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "AIX" ]; then
|
||||
BUILD_ARCH=POWER
|
||||
BUILD_OS=$UNAME_OS_ARCH
|
||||
BUILD_VER=`uname -v`.`uname -r`
|
||||
OS_CONFIG=${BUILD_OS}${BUILD_VER}
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "OSF1" ]; then
|
||||
BUILD_ARCH=ALPHA
|
||||
BUILD_OS=$UNAME_OS_ARCH
|
||||
BUILD_VER=$OS_RELEASE
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "IRIX64" -o "$UNAME_OS_ARCH" = "IRIX" ]; then
|
||||
BUILD_ARCH=MIPS
|
||||
BUILD_OS=IRIX
|
||||
BUILD_VER=$OS_RELEASE
|
||||
OS_CONFIG=${BUILD_OS}${OS_RELEASE}
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "BSD/386" ]; then
|
||||
BUILD_ARCH=x86
|
||||
BUILD_OS=BSDI
|
||||
BUILD_VER=$OS_RELEASE
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "FreeBSD" ]; then
|
||||
BUILD_ARCH=`uname -p`
|
||||
BUILD_OS=$UNAME_OS_ARCH
|
||||
BUILD_VER=$UNAME_OS_RELEASE
|
||||
if [ "$BUILD_ARCH" = "i386" ]; then
|
||||
BUILD_ARCH=x86
|
||||
fi
|
||||
OS_CONFIG=${BUILD_OS}${BUILD_VER}_${BUILD_ARCH}
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "SCO_SV" ]; then
|
||||
BUILD_ARCH=x86
|
||||
BUILD_OS=SCO
|
||||
BUILD_VER=$OS_RELEASE
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "UNIX_SV" ]; then
|
||||
# Check for braindamage
|
||||
grep NCR /etc/bcheckrc > /dev/null 2>&1
|
||||
BUILD_ARCH=x86
|
||||
if [ $? = 0 ]; then
|
||||
BUILD_OS=NCR
|
||||
else
|
||||
BUILD_OS=UNIXWARE
|
||||
fi
|
||||
BUILD_VER=$OS_RELEASE
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "NEWS-OS" ]; then
|
||||
BUILD_ARCH=`uname -p`
|
||||
BUILD_OS=SONY
|
||||
BUILD_VER=$OS_RELEASE
|
||||
|
||||
elif [ "$UNAME_OS_ARCH" = "UNIX_System_V" ]; then
|
||||
BUILD_ARCH=`uname -p`
|
||||
BUILD_OS=NEC
|
||||
BUILD_VER=$OS_RELEASE
|
||||
|
||||
elif [ $UNAME_OS_ARCH = Linux ]; then
|
||||
BUILD_ARCH=`uname -m`
|
||||
if [ -n "`echo $BUILD_ARCH | grep -e '86$'`" ] ; then
|
||||
BUILD_ARCH=x86
|
||||
fi
|
||||
BUILD_OS=$UNAME_OS_ARCH
|
||||
BUILD_VER=`echo $OS_RELEASE | cut -f1,2 -d.`
|
||||
OS_CONFIG=${BUILD_OS}${BUILD_VER}_${BUILD_ARCH}
|
||||
fi
|
||||
|
||||
case "$UNAME_OS_ARCH" in
|
||||
SINIX*|ReliantUNIX*)
|
||||
BUILD_ARCH=`uname -p`
|
||||
BUILD_OS="ReliantUNIX"
|
||||
BUILD_VER=$OS_RELEASE
|
||||
;;
|
||||
esac
|
||||
|
||||
#PLATFORM=${BUILD_ARCH}_${BUILD_OS}_${BUILD_VER}
|
||||
#echo $PLATFORM
|
||||
echo $OS_CONFIG
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/sh
|
||||
# The conZtents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Netscape Mailstone utility,
|
||||
# released March 17, 2000.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
# Marcel DePaolis <marcel@netcape.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU Public License (the "GPL"), in which case the
|
||||
# provisions of the GPL are applicable instead of those above.
|
||||
# If you wish to allow use of your version of this file only
|
||||
# under the terms of the GPL and not to allow others to use your
|
||||
# version of this file under the NPL, indicate your decision by
|
||||
# deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this
|
||||
# file under either the NPL or the GPL.
|
||||
#####################################################
|
||||
|
||||
# re-process a data run
|
||||
# by default, use the most recent one
|
||||
# Usage: process
|
||||
# or
|
||||
# Usage: process TIMESTAMP [args...]
|
||||
# or
|
||||
# Usage: process results/TIMESTAMP [args...]
|
||||
|
||||
if [ ! -x perl/bin/perl -o ! -f .license ] ; then # see if setup was ever run
|
||||
echo "Critical files are missing. Run setup."
|
||||
exit 2;
|
||||
fi
|
||||
|
||||
if [ $# -lt 1 ] ; then # do most recent run
|
||||
# since the directories are time stamps with fixed fields,
|
||||
# alphabetical order is also time order
|
||||
dir=`ls -d results/[0-9]*.[0-9]* | tail -1`
|
||||
else # use specified run
|
||||
if [ -d results/$1 ] ; then # timestamp
|
||||
dir=results/$1
|
||||
shift
|
||||
elif [ -d $1 ] ; then # results/timestamp
|
||||
dir=$1
|
||||
shift
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$dir" ] ; then
|
||||
if [ -f $dir/all.wld ] ; then # unified workload file
|
||||
perl/bin/perl -Ibin -- bin/process.pl -w $dir/all.wld "$@"
|
||||
else # BACK COMPATIBILITY form
|
||||
perl/bin/perl -Ibin -- bin/process.pl -c $dir/config.cfg "$@"
|
||||
fi
|
||||
else # pass in whatever they gave us
|
||||
perl/bin/perl -Ibin -- bin/process.pl "$@"
|
||||
fi
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env perl
|
||||
#!/usr/bin/perl
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
@@ -159,7 +159,7 @@ sub readClientCSV {
|
||||
}
|
||||
|
||||
foreach $section (@workload) { # find thread count for this client
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
next unless ($section->{sectionParams} =~ /$cli/);
|
||||
#print "Process $cli has threads $section->{THREADS}\n";
|
||||
$reportingClients += ($section->{THREADS})
|
||||
@@ -267,7 +267,7 @@ sub loadCSV {
|
||||
return 0 unless ($reportingClients > 0);
|
||||
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
my $slist = $section->{sectionParams};
|
||||
$slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
my @hlist = split /[\s,]/, $slist;
|
||||
@@ -322,7 +322,7 @@ my $doFull = 1; # re-processing is currently broken
|
||||
# $doFull = 1;
|
||||
# } else { # see if any source is newer than csv
|
||||
# foreach $section (@workload) {
|
||||
# next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
# next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
# my $slist = $section->{sectionParams};
|
||||
# $slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
# foreach $cli (split /[\s,]/, $slist) {
|
||||
|
||||
@@ -159,7 +159,7 @@ sub genTextReport {
|
||||
die "Couldn't open $resultstxt: $!";
|
||||
|
||||
# Store results as text
|
||||
printf RESULTSTXT "---- Mozilla MailStone Results $params{TSTAMP} ----\n";
|
||||
printf RESULTSTXT "---- Netscape MailStone Results $params{TSTAMP} ----\n";
|
||||
|
||||
printf RESULTSTXT "\t\t%s\n", $params{TITLE};
|
||||
printf RESULTSTXT "\t\t%s\n", $params{COMMENTS};
|
||||
@@ -283,7 +283,7 @@ sub genHTMLReportStart {
|
||||
<HTML>
|
||||
<A NAME=TitleSection>
|
||||
<TITLE>
|
||||
Mozilla MailStone Results $params{TSTAMP}
|
||||
Netscape MailStone Results $params{TSTAMP}
|
||||
</TITLE>
|
||||
</A>
|
||||
<HEAD>
|
||||
@@ -291,7 +291,7 @@ Mozilla MailStone Results $params{TSTAMP}
|
||||
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#FF0000" ALINK="#000088">
|
||||
<CENTER>
|
||||
<HR NOSHADE WIDTH="100%">
|
||||
<H1>Mozilla MailStone Results $params{TSTAMP}</H1>
|
||||
<H1>Netscape MailStone Results $params{TSTAMP}</H1>
|
||||
<H2>$params{TITLE}</H2>
|
||||
<I>$params{COMMENTS}</I>
|
||||
<HR WIDTH="100%">
|
||||
@@ -531,7 +531,7 @@ genHTMLReportStart();
|
||||
|
||||
my $graphCount = 0;
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /GRAPH/i);
|
||||
next unless ($section->{sectionTitle} =~ /GRAPH/o);
|
||||
my $name = $section->{sectionParams};
|
||||
$name =~ s/name=\s*//; # strip off initial bit
|
||||
my @varlist = split (/[\s,]+/, $section->{VARIABLES});
|
||||
@@ -586,7 +586,7 @@ if ($params{ADDGRAPHS}) { # pick up additional graphs
|
||||
my @graphs = ();
|
||||
readWorkloadFile ($params{ADDGRAPHS}, \@graphs);
|
||||
foreach $section (@graphs) {
|
||||
next unless ($section->{sectionTitle} =~ /GRAPH/i);
|
||||
next unless ($section->{sectionTitle} =~ /GRAPH/o);
|
||||
my $name = $section->{sectionParams};
|
||||
$name =~ s/name=\s*//; # strip off initial bit
|
||||
my @varlist = split (/[\s,]+/, $section->{VARIABLES});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env perl
|
||||
#!/usr/bin/perl
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
@@ -43,9 +43,6 @@ $mode = shift; # mode must be first
|
||||
# this parses the command line for -m machinefile
|
||||
# also sets many defaults
|
||||
do 'args.pl'|| die $@;
|
||||
sub warn_system;
|
||||
sub die_system;
|
||||
|
||||
parseArgs(); # parse command line
|
||||
|
||||
setConfigDefaults(); # setup RSH and RCP
|
||||
@@ -67,7 +64,7 @@ sub configClients {
|
||||
}
|
||||
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
my $slist = $section->{sectionParams};
|
||||
$slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
my $arch = "default OS";
|
||||
@@ -131,7 +128,8 @@ sub configUserLdif {
|
||||
print "$perlbin -Ibin -- bin/makeusers.pl $mode -w $params{WORKLOAD} -b '$basedn' -o $name $args\n";
|
||||
|
||||
print "\nGenerating $name (this can take a while)\n";
|
||||
warn_system "$perlbin -Ibin -- bin/makeusers.pl $mode -w $params{WORKLOAD} -b '$basedn' -o $name $args";
|
||||
system "$perlbin -Ibin -- bin/makeusers.pl $mode -w $params{WORKLOAD} -b '$basedn' -o $name $args"
|
||||
|| warn "$@";
|
||||
print "LDIF generation complete. See $name\n";
|
||||
print "\tSee the manual or INSTALL to create users using the LDIF file.\n";
|
||||
}
|
||||
@@ -203,14 +201,13 @@ sub configWorkload {
|
||||
# See if license file has been displayed
|
||||
if (($mode ne "cleanup") && (! -f ".license" )) {
|
||||
fileShow ("LICENSE");
|
||||
# SEAN: blow off annoying agreement message.
|
||||
# print "\nDo you agree to the terms of the license? (yes/no) ";
|
||||
# my $ans = <STDIN>;
|
||||
# print "\n";
|
||||
# unless ($ans =~ /^yes$/i) {
|
||||
# print "License not agreed to.\n";
|
||||
# exit 0;
|
||||
# }
|
||||
print "\nDo you agree to the terms of the license? (yes/no) ";
|
||||
my $ans = <STDIN>;
|
||||
print "\n";
|
||||
unless ($ans =~ /^yes$/i) {
|
||||
print "License not agreed to.\n";
|
||||
exit 0;
|
||||
}
|
||||
my ($sec, $min, $hour, $mday, $mon, $year) = localtime;
|
||||
open (LIC, ">.license");
|
||||
printf LIC "%04d$mon$mday$hour$min\n", $year+1900;
|
||||
@@ -268,7 +265,7 @@ if ($mode eq "timesync") {
|
||||
mkdir ("$resultbase", 0775);
|
||||
mkdir ("$tmpbase", 0775);
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
my $slist = $section->{sectionParams};
|
||||
$slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
foreach $cli (split /[\s,]/, $slist) {
|
||||
@@ -284,9 +281,9 @@ if ($mode eq "timesync") {
|
||||
exit 0 if ($mode =~ /cleanup$/);
|
||||
my $clipath = "bin/WINNT4.0/bin/mailclient.exe";
|
||||
print "Copying $clipath and message files to $cli\n";
|
||||
die_system "copy $clipath $params{TEMPDIR}";
|
||||
system "copy $clipath $params{TEMPDIR}";
|
||||
foreach $f (@files) {
|
||||
die_system "copy $f $params{TEMPDIR}";
|
||||
system "copy $f $params{TEMPDIR}";
|
||||
}
|
||||
exit 0; # without perl:fork, no more to do
|
||||
}
|
||||
@@ -294,7 +291,7 @@ if ($mode eq "timesync") {
|
||||
|
||||
# iterate over every client in the testbed, complete the cmd and rsh
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
my $slist = $section->{sectionParams};
|
||||
$slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
foreach $cli (split /[\s,]/, $slist) {
|
||||
@@ -306,35 +303,17 @@ foreach $section (@workload) {
|
||||
} elsif ($params{TEMPDIR}) {
|
||||
$tempdir = $params{TEMPDIR};
|
||||
}
|
||||
|
||||
my $cliarch = $section->{ARCH};
|
||||
|
||||
# presumed architecture for bin/mailclient on localhost:
|
||||
my $local_arch = `bin/nsarch`;
|
||||
chomp $local_arch;
|
||||
|
||||
# Try to determine arch if it hasn't been explicitly set.
|
||||
if (!$cliarch) {
|
||||
if ($cli =~ /localhost/) {
|
||||
$cliarch = `bin/nsarch`;
|
||||
chomp $cliarch;
|
||||
} else {
|
||||
$cliarch = `$rsh $cli sh < bin/nsarch`;
|
||||
chomp $cliarch;
|
||||
}
|
||||
}
|
||||
|
||||
# most time critical first
|
||||
if ($mode eq "timesync") {
|
||||
next if ($cli =~ /^localhost$/i); # dont reset our own time
|
||||
# run all these in parallel to minimize skew
|
||||
next if ($cliarch eq "NT4.0");
|
||||
next if ($section->{ARCH} eq "NT4.0");
|
||||
forkproc ($rsh, $cli, "date $systime");
|
||||
}
|
||||
|
||||
elsif ($mode eq "checktime") {
|
||||
# run all these in parallel to minimize skew
|
||||
forkproc ($rsh, $cli, ($cliarch eq "NT4.0")
|
||||
forkproc ($rsh, $cli, ($section->{ARCH} eq "NT4.0")
|
||||
? "time" : "date",
|
||||
"/dev/null", "$tmpbase/$cli.tim");
|
||||
}
|
||||
@@ -343,60 +322,34 @@ foreach $section (@workload) {
|
||||
my ($clibin) = split /\s/, (($section->{COMMAND})
|
||||
? $section->{COMMAND}
|
||||
: $params{CLIENTCOMMAND});
|
||||
my $clipath = ''; # do nothing by default
|
||||
|
||||
# Look for architecture-specific binary.
|
||||
if ($cliarch) {
|
||||
|
||||
# fallback to just os-name if we can't find an exact match.
|
||||
my $approx = $cliarch;
|
||||
$approx =~ s/^(\D+).*/$1/;
|
||||
my $approx_bin = <"bin/${approx}*/bin/$clibin">;
|
||||
|
||||
if (-x "bin/$cliarch/bin/$clibin") {
|
||||
# exact match.
|
||||
$clipath = "bin/$cliarch/bin/$clibin";
|
||||
} elsif (-x $approx_bin) {
|
||||
# approximate match
|
||||
$clipath = $approx_bin;
|
||||
} elsif ($local_arch =~ /^$approx/) {
|
||||
# same arch as localhost
|
||||
$clipath = "bin/mailclient";
|
||||
my $clipath = "bin/$clibin";
|
||||
if ($section->{ARCH}) {
|
||||
if (-x "bin/$section->{ARCH}/bin/$clibin") {
|
||||
$clipath="bin/$section->{ARCH}/bin/$clibin";
|
||||
} else {
|
||||
print STDERR
|
||||
"Requested OS $cliarch for $cli not found. ",
|
||||
"Not copying binary.\n";
|
||||
print "Requested OS $section->{ARCH} $cli not found. Using default.\n";
|
||||
}
|
||||
} else {
|
||||
# arch not found
|
||||
print STDERR "Cannot determine architecture for $cli. ",
|
||||
"Not copying binary.\n";
|
||||
}
|
||||
# See if we have anything to copy:
|
||||
if ("$clipath @files" !~ /\S/) {
|
||||
print STDERR "Nothing to copy to $cli. Skipping.\n";
|
||||
next;
|
||||
}
|
||||
my $rdir = ($tempdir) ? "$tempdir/" : ".";
|
||||
# chmod so that the remote files can be easily cleaned up
|
||||
my $rcmd = "chmod g+w @files $clibin; uname -a";
|
||||
$rcmd = "cd $tempdir; " . $rcmd if ($tempdir);
|
||||
$rdir =~ s!/!\\!g if ($cliarch eq "NT4.0");
|
||||
$rdir =~ s!/!\\!g if ($section->{ARCH} eq "NT4.0");
|
||||
if ($cli =~ /^localhost$/i) {
|
||||
die "TEMPDIR must be set for 'localhost'\n"
|
||||
unless ($tempdir);
|
||||
die "Invalid local NT copy. Should never get here.\n"
|
||||
if ($cliarch eq "NT4.0"); # should never happen
|
||||
if ($section->{ARCH} eq "NT4.0"); # should never happen
|
||||
print "Copying $clipath and message files to $rdir\n";
|
||||
die_system ("$cpcmd @msgs $clipath $rdir");
|
||||
die_system ($rcmd);
|
||||
system ("$cpcmd @msgs $clipath $rdir");
|
||||
system ($rcmd);
|
||||
} else {
|
||||
print "$rcp $clipath @msgs $cli:$rdir\n" if ($params{DEBUG});
|
||||
print "Copying $clipath and message files to $cli:$rdir\n";
|
||||
warn_system (split (/\s+/, $rcp), $clipath, @msgs, "$cli:$rdir");
|
||||
next if ($cliarch eq "NT4.0"); # chmod not valid
|
||||
system (split (/\s+/, $rcp), $clipath, @msgs, "$cli:$rdir");
|
||||
next if ($section->{ARCH} eq "NT4.0"); # chmod not valid
|
||||
print "rcmd='$rcmd'\n" if ($params{DEBUG});
|
||||
die_system (split (/\s+/, $rsh), $cli, $rcmd);
|
||||
system (split (/\s+/, $rsh), $cli, $rcmd);
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
@@ -404,29 +357,29 @@ foreach $section (@workload) {
|
||||
elsif ($mode eq "cleanup") {
|
||||
if ($params{DEBUG}) { # get debug files
|
||||
print "Cleaning up debug files on $cli\n";
|
||||
my $rcmd = ($cliarch eq "NT4.0") ? "DEL" : "$rmcmd";
|
||||
my $rcmd = ($section->{ARCH} eq "NT4.0") ? "DEL" : "$rmcmd";
|
||||
$rmcmd .= " mstone-debug.[0-9]*";
|
||||
$rcmd = "cd $tempdir; " . $rcmd if ($tempdir);
|
||||
$rcmd =~ s/;/&&/g if ($cliarch eq "NT4.0");
|
||||
$rcmd =~ s/;/&&/g if ($section->{ARCH} eq "NT4.0");
|
||||
if ($cli =~ /^localhost$/i) {
|
||||
die "TEMPDIR must be set for 'localhost'\n"
|
||||
unless ($tempdir);
|
||||
warn_system ($rcmd);
|
||||
system ($rcmd);
|
||||
} else {
|
||||
warn_system (split (/\s+/, $rsh), $cli, $rcmd);
|
||||
system (split (/\s+/, $rsh), $cli, $rcmd);
|
||||
}
|
||||
} else {
|
||||
print "Cleaning $cli\n";
|
||||
my $rcmd = ($cliarch eq "NT4.0") ? "DEL" : "$rmcmd";
|
||||
my $rcmd = ($section->{ARCH} eq "NT4.0") ? "DEL" : "$rmcmd";
|
||||
$rcmd .= " $clibin @files";
|
||||
$rcmd = "cd $tempdir; " . $rcmd if ($tempdir);
|
||||
$rcmd =~ s/;/&&/g if ($cliarch eq "NT4.0");
|
||||
$rcmd =~ s/;/&&/g if ($section->{ARCH} eq "NT4.0");
|
||||
if ($cli =~ /^localhost$/i) {
|
||||
die "TEMPDIR must be set for 'localhost'\n"
|
||||
unless ($tempdir);
|
||||
warn_system ($rcmd);
|
||||
system ($rcmd);
|
||||
} else {
|
||||
warn_system (split (/\s+/, $rsh), $cli, $rcmd);
|
||||
system (split (/\s+/, $rsh), $cli, $rcmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,7 +402,7 @@ if (($mode eq "timesync") || ($mode eq "checktime")) {
|
||||
if ($mode eq "checktime") {
|
||||
print "Time from each client:\n";
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/o);
|
||||
my $slist = $section->{sectionParams};
|
||||
$slist =~ s/HOSTS=\s*//; # strip off initial bit
|
||||
foreach $cli (split /[\s,]/, $slist) {
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
use Thread qw(async);
|
||||
use FileHandle qw(_IOLBF);
|
||||
use Socket;
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
# options
|
||||
my $maxconn = SOMAXCONN;
|
||||
my $t_banner = 0;
|
||||
my $t_from = 0;
|
||||
my $t_rcpt = 0;
|
||||
my $t_dot = 0;
|
||||
my $port = 25;
|
||||
my $cs = '';
|
||||
my $log = '';
|
||||
my $proto = getprotobyname('tcp');
|
||||
|
||||
# statistics
|
||||
my ($cmds, $errs, $bytesw, $bytesr, $msgs);
|
||||
|
||||
GetOptions('maxconn:i' => \$maxconn,
|
||||
'banner-delay:i' => \$t_banner,
|
||||
'from-delay:i' => \$t_from,
|
||||
'rcpt-delay:i' => \$t_rcpt,
|
||||
'dot-delay:i' => \$t_dot,
|
||||
'log:s' => \$log,
|
||||
'checksums:s' => sub { use Digest::MD5; $cs = $_[0]; })
|
||||
|| &usage;
|
||||
|
||||
if (@ARGV == 1) {
|
||||
($port) = @ARGV;
|
||||
}
|
||||
|
||||
if ($log) {
|
||||
if (open(LOG, ">$log")) {
|
||||
print STDERR "Logging messages to $log\n";
|
||||
} else {
|
||||
warn ("Cannot open logfile $log\n");
|
||||
$log = '';
|
||||
}
|
||||
}
|
||||
|
||||
socket(S, PF_INET, SOCK_STREAM, $proto) || die $!;
|
||||
setsockopt(S, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die $!;
|
||||
|
||||
(bind(S, sockaddr_in($port, INADDR_ANY))
|
||||
&& listen(S, $maxconn))
|
||||
|| die $!;
|
||||
|
||||
my $addr;
|
||||
my $fh = new FileHandle;
|
||||
my $cnt = 0;
|
||||
|
||||
$SIG{INT} = sub { close(LOG); print STDERR "done\n"; exit 0; };
|
||||
|
||||
while(my $addr = accept($fh, S)) {
|
||||
if (++$cnt % 100 == 0) {
|
||||
print STDERR "$cnt\r";
|
||||
}
|
||||
my $thr = async { do_smtp($addr, $fh); };
|
||||
$thr->join;
|
||||
$fh = new FileHandle;
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
print STDERR <<EOS;
|
||||
Usage: $0 [options] [port]
|
||||
EOS
|
||||
exit -1;
|
||||
}
|
||||
|
||||
sub netline
|
||||
{
|
||||
my $fh = shift;
|
||||
my $line = $fh->getline;
|
||||
$line =~ s/\r\n$// if $line;
|
||||
$line;
|
||||
}
|
||||
|
||||
sub millisleep
|
||||
{
|
||||
my $t = shift;
|
||||
select(undef, undef, undef, $t) if $t > 0;
|
||||
}
|
||||
|
||||
sub netprint($@)
|
||||
{
|
||||
my ($fh, @stuff) = @_;
|
||||
foreach (@_) {
|
||||
s/([^\r])\n/$1\r\n/g;
|
||||
$fh->print($_);
|
||||
}
|
||||
}
|
||||
|
||||
sub do_smtp
|
||||
{
|
||||
my ($addr, $s) = @_;
|
||||
my $buf;
|
||||
my ($port, $iaddr) = sockaddr_in($addr);
|
||||
my $name = gethostbyaddr($iaddr, AF_INET);
|
||||
$s->setvbuf($buf, _IOLBF, 1024);
|
||||
|
||||
millisleep($t_banner);
|
||||
$s->print("220 wazzup, bro?\r\n");
|
||||
my %state = ('conn' => $s,
|
||||
'host' => $name);
|
||||
my %funcs = ('helo' => \&do_helo,
|
||||
'ehlo' => \&do_helo,
|
||||
'word' => \&do_helo,
|
||||
|
||||
'quit' => \&do_quit,
|
||||
'latr' => \&do_quit,
|
||||
|
||||
'mail' => \&do_from,
|
||||
'rcpt' => \&do_rcpt,
|
||||
'data' => \&do_data,
|
||||
'rset' => \&do_ok,
|
||||
'vrfy' => \&do_ok,
|
||||
'noop' => \&do_ok,
|
||||
);
|
||||
while (my $line = netline($s))
|
||||
{
|
||||
my ($cmd, $arg) = ($line =~ /^\s*(\S+)\s*(.*)$/);
|
||||
die "cmd = `$cmd'" unless ($cmd = lc($cmd));
|
||||
# fail 1% of commands
|
||||
if ($funcs{$cmd}) {
|
||||
&{$funcs{$cmd}}(\%state, $cmd, $arg, \%funcs);
|
||||
} else {
|
||||
$s->print("500 5.0.0 no. Just... no.\r\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub already_said_that
|
||||
{
|
||||
my ($state, $cmd, $arg) = @_;
|
||||
$state->{conn}->print("503 5.0.0 Dude, you already said that.\r\n");
|
||||
}
|
||||
|
||||
sub do_helo
|
||||
{
|
||||
my ($state, $cmd, $arg) = @_;
|
||||
$state->{helohost} = $arg;
|
||||
die unless $cmd;
|
||||
if ($cmd eq 'helo') {
|
||||
if ($arg eq $state->{host}) {
|
||||
$state->{conn}->print("221 hello Mr. Honest\r\n");
|
||||
} else {
|
||||
$state->{conn}->print("221 We know where you live, $state->{iaddr}\r\n");
|
||||
}
|
||||
} elsif ($cmd eq 'ehlo') {
|
||||
my $esmtp = <<EOS;
|
||||
250-localhost is pleased to make your acquaintance, and offers:
|
||||
250 8bitmime
|
||||
EOS
|
||||
if ($arg) {
|
||||
netprint($state->{conn}, $esmtp);
|
||||
} else {
|
||||
$state->{conn}->print("501 5.0.0 tell me more...\r\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$state->{conn}->print("221 2.0.0 peace brother\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
sub do_quit
|
||||
{
|
||||
my ($state, $cmd) = @_;
|
||||
$state->{conn}->print( "221 2.0.0 drop in any time\r\n");
|
||||
close ($state->{conn});
|
||||
}
|
||||
|
||||
sub do_from
|
||||
{
|
||||
my ($state, $cmd, $args, $funcs) = @_;
|
||||
millisleep($t_from);
|
||||
$state->{conn}->print( "250 2.1.0 Okay, keep talking\r\n");
|
||||
$funcs->{rcpt} = \&do_rcpt;
|
||||
}
|
||||
|
||||
sub do_rcpt
|
||||
{
|
||||
my ($state, $cmd, $args, $funcs) = @_;
|
||||
my ($rcpt) = ($args =~ /to\:\s*(.+)/i);
|
||||
millisleep($t_rcpt);
|
||||
$state->{conn}->print("250 2.1.5 ${rcpt}'s cool\r\n");
|
||||
$funcs->{data} = \&do_data;
|
||||
}
|
||||
|
||||
sub do_data
|
||||
{
|
||||
my ($state, $cmd, $args, $funcs) = @_;
|
||||
$state->{conn}->print( "354 up to the dot...\r\n");
|
||||
if ($cs) {
|
||||
my $line;
|
||||
my $md5 = Digest::MD5->new;
|
||||
# skip headers
|
||||
header: while ($_ = netline($state->{conn})) {
|
||||
last header if /^$/;
|
||||
last body if /^\.$/;
|
||||
}
|
||||
|
||||
body: while ($_ = $state->{conn}->getline) {
|
||||
if (/^=CS=MD5=(.+)\r/) {
|
||||
my $sum = $1;
|
||||
my $end = netline($state->{conn});
|
||||
|
||||
if ($end ne '.') {
|
||||
print STDERR "Fake checksum?: $sum\n";
|
||||
while (netline($state->{conn}) ne '.') { }
|
||||
} elsif (lc($sum) eq lc($md5->hexdigest)) {
|
||||
# print STDERR "MD5 sum OK.\n";
|
||||
} else {
|
||||
print STDERR "MD5 sum mismatch: $sum, ",
|
||||
$md5->hexdigest, "\n";
|
||||
}
|
||||
last body;
|
||||
} elsif (/^\.\r$/) {
|
||||
print STDERR "no checksum\n" if $cs =~ /^r/;
|
||||
last body;
|
||||
}
|
||||
print LOG $_ if $log;
|
||||
$md5->add($_);
|
||||
}
|
||||
print LOG ".\r\n" if $log;
|
||||
} else {
|
||||
local ($/) = "\r\n.\r\n";
|
||||
$state->{conn}->getline;
|
||||
}
|
||||
millisleep($t_dot);
|
||||
if (rand() % 100 == 0) {
|
||||
$state->{conn}->print("451 ohshit\r\n");
|
||||
} else {
|
||||
$state->{conn}->print("250 2.0.0 I will deliver\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
sub do_ok
|
||||
{
|
||||
my ($state) = @_;
|
||||
$state->{conn}->print("220 uhhuh\r\n");
|
||||
}
|
||||
@@ -1,825 +0,0 @@
|
||||
# util.pl -- utilities which used to live in bin/args.pl
|
||||
|
||||
sub my_system {
|
||||
my ($file, $line);
|
||||
$file = shift;
|
||||
$line = shift;
|
||||
my $ret;
|
||||
if (($ret = system(@_)) != 0) {
|
||||
my $msg = "$file:$line: @_\n\t";
|
||||
my ($excode, $sig, $cored) = ($ret >> 8, $ret & 127, $ret & 128);
|
||||
if ($sig) {
|
||||
$msg .= "died with signal $sig";
|
||||
$msg .= ' (core dumped)' if ($cored);
|
||||
$msg .= "\n";
|
||||
} else {
|
||||
$msg .= "exited abnormally with code $excode\n";
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
undef;
|
||||
}
|
||||
|
||||
sub warn_system {
|
||||
my ($pack, $file, $line) = caller;
|
||||
my $msg = my_system($file, $line, @_);
|
||||
warn $msg if $msg;
|
||||
}
|
||||
|
||||
sub die_system {
|
||||
my ($pack, $file, $line) = caller;
|
||||
my $msg = my_system($file, $line, @_);
|
||||
die $msg if $msg;
|
||||
}
|
||||
|
||||
# Utility functions
|
||||
# Create a unique hash array. Programming Perl, 2nd edition, p291 (p217?)
|
||||
package ArrayInstance;
|
||||
sub new {
|
||||
my $type = shift;
|
||||
my %params = @_;
|
||||
my $self = {};
|
||||
return bless $self, $type;
|
||||
}
|
||||
|
||||
package main;
|
||||
|
||||
# run a command in the background, return its PID
|
||||
# Uses fork: will not run on NT in perl 5.004
|
||||
# if the server is "localhost", ignore the rcmd part
|
||||
# if stdin, stdout, and/or stderr is set, redirect those for the sub process
|
||||
sub forkproc {
|
||||
my $rcmd = shift;
|
||||
my $server = shift;
|
||||
my $command = shift;
|
||||
my $stdin = shift;
|
||||
my $stdout = shift;
|
||||
my $stderr = shift;
|
||||
|
||||
if (my $pid = fork()) {
|
||||
return $pid; # parent
|
||||
}
|
||||
|
||||
# rest of this is in the child
|
||||
if ($stdin) { # redirect stdin if needed
|
||||
close (STDIN);
|
||||
open STDIN, "<$stdin"
|
||||
|| die "Couldn't open $stdin for input\n";
|
||||
}
|
||||
|
||||
if ($stdout) { # redirect stdout if needed
|
||||
close (STDOUT);
|
||||
open STDOUT, ">>$stdout"
|
||||
|| die "Couldn't open $stdout for output\n";
|
||||
}
|
||||
|
||||
if ($stderr) { # redirect stderr if needed
|
||||
close (STDERR);
|
||||
open STDERR, ">>$stderr"
|
||||
|| die "Couldn't open $stderr for output\n";
|
||||
}
|
||||
|
||||
if ($server =~ /^localhost$/i) {
|
||||
exec $command;
|
||||
die "Coundn't exec $command:$!\n";
|
||||
} else {
|
||||
exec split (/\s+/, $rcmd), $server, $command;
|
||||
die "Coundn't exec $rcmd $server $command:$!\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Relocate file to tmp directory (if it is in the results directory),
|
||||
# and put a ~ on the end of it.
|
||||
# ASSUMES tmp and results are on the same partition (on NT, same drive).
|
||||
# Usage: fileBackup (filename)
|
||||
sub fileBackup {
|
||||
my $filename = shift;
|
||||
my $bfile = $filename;
|
||||
|
||||
(-f $filename) || return 0; # file doent exist
|
||||
$bfile =~ s/$resultbase/$tmpbase/; # move to tmp
|
||||
$bfile .= "~"; # indicate that this is a backup
|
||||
(-f $bfile) && unlink ($bfile);
|
||||
#print "Backing up $filename to $bfile\n"; # DEBUG
|
||||
rename ($filename, $bfile) || unlink ($filename);
|
||||
}
|
||||
|
||||
# Insert text into a file after a tagline
|
||||
# fileInsertAfter (filename, tagstring, newtext)
|
||||
sub fileInsertAfter {
|
||||
my $filename = shift || die "fileInsertAfter: missing filename";
|
||||
my $tagline = shift || die "fileInsertAfter: missing tagline";
|
||||
my $newtext = shift || die "fileInsertAfter: missing text";
|
||||
my $foundit = 0;
|
||||
|
||||
open(OLD, "<$filename") ||
|
||||
open(OLD, "gunzip -c $filename |") ||
|
||||
die "fileInsertAfter: Could not open input $filename: $!";
|
||||
open(NEW, ">$filename+") ||
|
||||
die "fileInsertAfter: Could not open output $filename+: $!";
|
||||
|
||||
while (<OLD>) {
|
||||
print NEW $_; # copy (including tagline)
|
||||
|
||||
next unless (/$tagline/); # matched tagline
|
||||
|
||||
print NEW $newtext; # insert new text
|
||||
$foundit++;
|
||||
last; # only change first occurance
|
||||
}
|
||||
|
||||
if ($foundit) { # copy rest of file
|
||||
while (<OLD>) {
|
||||
print NEW $_;
|
||||
}
|
||||
}
|
||||
|
||||
close (OLD);
|
||||
close (NEW);
|
||||
if ($foundit) {
|
||||
fileBackup ($filename);
|
||||
rename ("$filename+", "$filename");
|
||||
#print "Updated $filename\n"; # DEBUG
|
||||
return $foundit;
|
||||
} else {
|
||||
($params{DEBUG}) && print "No change to $filename\n"; # DEBUG
|
||||
unlink ("$filename+");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Do text for text replacements in a file.
|
||||
# Perl wildcards are automatically quoted.
|
||||
# fileReplace (filename, matchPat, oldtext, newtext)
|
||||
sub fileReplaceText {
|
||||
my $filename = shift || die "fileReplaceText: missing filename";
|
||||
my $tagline = shift || die "fileReplaceText: missing tagline ($filename)";
|
||||
my $oldtext = shift;
|
||||
my $newtext = shift;
|
||||
my $foundit = 0;
|
||||
|
||||
return if ($newtext eq ""); # nothing to do
|
||||
return if ($oldtext eq ""); # nothing can be done
|
||||
|
||||
open(OLD, "<$filename") ||
|
||||
open(OLD, "gunzip -c $filename |") ||
|
||||
die "fileReplaceText: Could not open input $filename: $!";
|
||||
open(NEW, ">$filename+") ||
|
||||
die "fileReplaceText: Could not open output $filename+: $!";
|
||||
|
||||
$oldtext =~ s/([][{}*+?^.\/])/\\$1/g; # quote regex syntax
|
||||
|
||||
while (<OLD>) {
|
||||
if (/$tagline/i) { # matched tagline
|
||||
$foundit++;
|
||||
s/$oldtext/$newtext/; # do the replace
|
||||
}
|
||||
print NEW $_;
|
||||
}
|
||||
|
||||
close (OLD);
|
||||
close (NEW);
|
||||
if ($foundit) {
|
||||
fileBackup ($filename);
|
||||
rename ("$filename+", "$filename");
|
||||
#print "Updated $filename\n"; # DEBUG
|
||||
return $foundit;
|
||||
} else {
|
||||
($params{DEBUG}) && print "No change to $filename\n"; # DEBUG
|
||||
unlink ("$filename+");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# copy a file to a new name. Handles possible compression. OS independent.
|
||||
# fileCopy (filename, newname)
|
||||
sub fileCopy {
|
||||
my $filename = shift || die "fileReplaceText: missing filename";
|
||||
my $newname = shift || die "fileReplaceText: missing newname ($filename)";
|
||||
|
||||
open(OLD, "<$filename") ||
|
||||
open(OLD, "gunzip -c $filename |") ||
|
||||
die "fileReplaceText: Could not open input $filename: $!";
|
||||
open(NEW, ">$newname") ||
|
||||
die "fileReplaceText: Could not open output $newname: $!";
|
||||
|
||||
while (<OLD>) { # copy it
|
||||
print NEW $_;
|
||||
}
|
||||
|
||||
close (OLD);
|
||||
close (NEW);
|
||||
return 0;
|
||||
}
|
||||
|
||||
# display a file to STDOUT. Handles possible compression
|
||||
sub fileShow {
|
||||
my $filename = shift || die "fileShow: missing filename";
|
||||
open(SHOWIT, "<$filename") ||
|
||||
open(SHOWIT, "gunzip -c $filename.gz |") ||
|
||||
die "fileShow: Couldn't open $filename: $!";
|
||||
while (<SHOWIT>) { print; }
|
||||
close(SHOWIT);
|
||||
}
|
||||
|
||||
# sub function to figure time extents
|
||||
# (start, end) = dataMinMax counterName \@protocols oldstarttime oldendtime
|
||||
# Use 0 for uninitialized start or end
|
||||
sub dataMinMax {
|
||||
my $name = shift;
|
||||
my $protos = shift;
|
||||
my $start = shift;
|
||||
my $end = shift;
|
||||
|
||||
# make global
|
||||
# create the plot script and data files
|
||||
# Figure out the encompassing time extent
|
||||
foreach $p (@$protos) { # create the plot data files
|
||||
my @times = sort numeric keys %{ $graphs{$p}->{$name}};
|
||||
if ($#times <= 0) {
|
||||
next;
|
||||
}
|
||||
if (($start == 0) || ($times[0] < $start)) {
|
||||
$start = $times[0];
|
||||
}
|
||||
if (($end == 0) || ($times[0] > $end)) {
|
||||
$end = $times[$#times];
|
||||
}
|
||||
}
|
||||
#printf ("Data $name start=$start end=$end (%d points)...\n",
|
||||
# $end - $start);
|
||||
return ($start, $end);
|
||||
}
|
||||
|
||||
# simple function to formatted a number into n, n K, n M, or n G
|
||||
sub kformat {
|
||||
my $n = shift;
|
||||
my $r = "";
|
||||
if ($n > (1024*1024*1024)) {
|
||||
$r = sprintf "%.2fG", $n / (1024*1024*1024);
|
||||
} elsif ($n > (1024*1024)) {
|
||||
$r = sprintf "%.2fM", $n / (1024*1024);
|
||||
} elsif ($n > 1024) {
|
||||
$r = sprintf "%.2fK", $n / 1024;
|
||||
} else {
|
||||
$r = sprintf "%d ", $n;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
# simple function to formatted a time into Ns, Nms, or Nus
|
||||
# the goal is to make a table of timss uncluttered and easy to read
|
||||
# I dont convert to minutes or hours because the non-1000x multipliers
|
||||
# are hard to back solve in your head for comparisons
|
||||
sub tformat {
|
||||
my $n = shift;
|
||||
my $r = "";
|
||||
if ($n == 0.0) {
|
||||
$r = "0.0"; # make exactly 0 explicit
|
||||
} elsif ($n < 0.001) {
|
||||
$r = sprintf "%.2fus", $n * 1000 * 1000;
|
||||
} elsif ($n < 1.0) {
|
||||
$r = sprintf "%.2fms", $n * 1000;
|
||||
} elsif ($n >= 1000.0) {
|
||||
$r = sprintf "%.0fs", $n;
|
||||
} elsif ($n >= 100.0) {
|
||||
$r = sprintf "%.1fs", $n;
|
||||
} else {
|
||||
$r = sprintf "%.3fs", $n;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
#Usage: commify (1234567) returns 1,234,567
|
||||
sub commify { # perl cookbook p64-65
|
||||
my $text = reverse $_[0];
|
||||
$text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
|
||||
return scalar reverse $text;
|
||||
}
|
||||
|
||||
# subroutine to enable numeric sorts. Programming Perl p218
|
||||
# Use: sort numeric ...
|
||||
sub numeric { $a <=> $b; }
|
||||
|
||||
# on NT, turn slash to backslash, then print. Else print.
|
||||
sub pathprint {
|
||||
my $str = shift;
|
||||
$str =~ s!/!\\!g if ($params{NT}); # turn slash to back slash
|
||||
print $str;
|
||||
}
|
||||
|
||||
# figureTimeNumber number
|
||||
# Given an number like: 60m, 1h, 100s, 4d, 200
|
||||
# Return 60, 1, 100, 4, 200
|
||||
sub figureTimeNumber {
|
||||
my $arg = shift;
|
||||
|
||||
($arg =~ /([0-9]+)(s|sec|second|seconds|m|min|minute|minutes|h|hr|hour|hours|d|day|days)$/i)
|
||||
&& return $1;
|
||||
return $arg; # return default
|
||||
}
|
||||
|
||||
# figureTimeUnits number, default
|
||||
# Given an number like: 60m, 1h, 100s, 4d
|
||||
# Return a string of minutes, hours, seconds, days
|
||||
# Else return the second argument
|
||||
sub figureTimeUnits {
|
||||
my $arg = shift;
|
||||
|
||||
($arg =~ /(s|sec|second|seconds)$/i) && return "seconds";
|
||||
($arg =~ /(m|min|minute|minutes)$/i) && return "minutes";
|
||||
($arg =~ /(h|hr|hour|hours)$/i) && return "hours";
|
||||
($arg =~ /(d|day|days)$/i) && return "days";
|
||||
|
||||
return shift; # return default
|
||||
}
|
||||
|
||||
# figureTimeSeconds number, defaultUnits
|
||||
# Given an number like: 60m, 2h, 100s, 4d
|
||||
# Return 60*60, 2*60*60, 100, 4*24*60*60
|
||||
sub figureTimeSeconds {
|
||||
my $arg = shift;
|
||||
|
||||
($arg =~ /([0-9]+)(s|sec|second|seconds)$/i) && return $1;
|
||||
($arg =~ /([0-9]+)(m|min|minute|minutes)$/i) && return (60*$1);
|
||||
($arg =~ /([0-9]+)(h|hr|hour|hours)$/i) && return (60*60*$1);
|
||||
($arg =~ /([0-9]+)(d|day|days)$/i) && return (24*60*60*$1);
|
||||
|
||||
if ($_) {
|
||||
my $def = shift;
|
||||
return $arg * figureTimeSeconds ("1$def"); # return scaled by default
|
||||
} else {
|
||||
return $arg; # return it
|
||||
}
|
||||
}
|
||||
|
||||
# BACK COMPATIBILITY (everything now in the workload file)
|
||||
# read the testbed conf file, convert to workload sections
|
||||
# machine, how many processes, how many threads/proc, arch
|
||||
# only the first 2 fields are required. Lines starting with # are ignored.
|
||||
# You can include other files using <include conf/filename.tbd>
|
||||
# exampe:
|
||||
# client1 5 10 SunOS5.5.1
|
||||
sub readTestbedFile {
|
||||
my $filename = shift;
|
||||
foreach $section (@workload) {
|
||||
next unless ($section->{sectionTitle} =~ /CLIENT/i);
|
||||
print "Testbed $filename skipped, clients read in workload\n";
|
||||
return 1; # clients already read in workload
|
||||
}
|
||||
|
||||
my $level = 0;
|
||||
if ($_) {
|
||||
$level = 1 + shift;
|
||||
die "Too many nested includes ($level) in $filename!"
|
||||
unless ($level < 100);
|
||||
}
|
||||
my $handle = "$filename$level";
|
||||
open($handle, "<$filename") ||
|
||||
open($handle, "gunzip -c $filename.gz |") ||
|
||||
die "Couldn't open testbed $filename: $!";
|
||||
|
||||
while(<$handle>) {
|
||||
chomp;
|
||||
|
||||
s/#.*//; # strip any comments from line
|
||||
|
||||
m/^\s*$/o && next; # continue if blank line
|
||||
|
||||
# handle include statement
|
||||
if (m/^<(include|INCLUDE)\s+([^\s]+)\s*>/o) {
|
||||
#print "Including $2 from $filename\n";
|
||||
readTestbedFile ($2, $level) || die;
|
||||
next;
|
||||
}
|
||||
|
||||
# get the server name and number of processes
|
||||
my @line = split(/\s+/);
|
||||
# create CLIENT entry in workload
|
||||
my $sparm = ArrayInstance->new();
|
||||
if ($line[1]) {
|
||||
$sparm->{"sectionTitle"} = "CLIENT";
|
||||
$sparm->{"sectionParams"} = "HOSTS=$line[0]";
|
||||
$sparm->{"PROCESSES"} = $line[1];
|
||||
$sparm->{"THREADS"} = $line[2] if ($line[2]);
|
||||
$sparm->{"ARCH"} = $line[3] if ($line[3]);
|
||||
} else {
|
||||
$sparm->{"sectionTitle"} = "MONITOR";
|
||||
$sparm->{"sectionParams"} = "HOSTS=$line[0]";
|
||||
$sparm->{"COMMAND"} = $line[2];
|
||||
}
|
||||
($params{DEBUG})
|
||||
&& print "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
|
||||
push @workload, $sparm;
|
||||
}
|
||||
close ($handle);
|
||||
}
|
||||
|
||||
# BACK COMPATIBILITY (everything now in the saved workload file)
|
||||
# This is now only needed to process mailstone4.1 runs
|
||||
sub readConfigFile {
|
||||
my $filename = shift;
|
||||
open(CONFIG, "<$filename") ||
|
||||
open(CONFIG, "gunzip -c $filename.gz |") ||
|
||||
die "Couldn't open config file $filename: $!";
|
||||
|
||||
while(<CONFIG>) {
|
||||
chomp;
|
||||
|
||||
s/#.*//; # strip any comments from line
|
||||
|
||||
m/^\s*$/o && next; # continue if blank line
|
||||
|
||||
# get the property and value
|
||||
my @line = split(/=/);
|
||||
$params{$line[0]} = $line[1];
|
||||
}
|
||||
close CONFIG;
|
||||
}
|
||||
|
||||
# read the workload file and store it as a list of hashes
|
||||
# Each hash always has the fields: sectionTitle and sectionParams
|
||||
# usage: readWorkloadFile filename, \@list
|
||||
sub readWorkloadFile {
|
||||
my $filename = shift || die "readWorkloadFile: Missing file name";
|
||||
my $plist = shift || die "readWorkloadFile: Missing return list";
|
||||
my $level = 0; # file inclusion level
|
||||
my @handles;
|
||||
|
||||
my $fh = "$filename$level";
|
||||
|
||||
($params{DEBUG}) && print "Reading workload from $filename.\n";
|
||||
open($fh, "<$filename") ||
|
||||
open($fh, "gunzip -c $filename.gz |") ||
|
||||
die "readWorkloadFile Couldn't open testbed $filename: $!";
|
||||
$includedFiles{$filename} = 1; # mark file as included
|
||||
|
||||
my $sparm=0;
|
||||
my $conline = "";
|
||||
|
||||
while($fh) {
|
||||
while(<$fh>) {
|
||||
s/#.*//; # strip any comments from line (quoting?)
|
||||
s/\s*$//; # strip trailing white space
|
||||
if ($conline) { # utilize line continue
|
||||
$_ = $conline . "\\\n" . $_;
|
||||
$conline = "";
|
||||
}
|
||||
if (m/\\$/o) { # check for quoted line continue
|
||||
s/\\$//; #
|
||||
$conline = $_;
|
||||
next;
|
||||
}
|
||||
s/^\s*//; # strip initial white space
|
||||
m/^$/o && next; # continue if blank line
|
||||
|
||||
# handle include and includeOnce statements
|
||||
if ((m/^<(include)\s+(\S+)\s*>/i)
|
||||
|| (m/^<(includeonce)\s+(\S+)\s*>/i)) {
|
||||
my $incfile = $2;
|
||||
if (($1 =~ m/^includeonce/i) && ($includedFiles{$incfile})) {
|
||||
($params{DEBUG})
|
||||
&& print "readWorkloadFile:includeOnce $incfile already read.\n";
|
||||
next;
|
||||
}
|
||||
($params{DEBUG})
|
||||
&& print "readWorkloadFile include $incfile from $filename.\n";
|
||||
$includedFiles{$incfile} = 1; # mark file
|
||||
push @handles, $fh; # push current handle on to stack
|
||||
if ($level++ > 99) { # check recursion and make handles unique
|
||||
die "readWorkloadFile: include level too deep: $filename $level\n";
|
||||
}
|
||||
$fh = "$incfile$level";
|
||||
open($fh, "<$incfile") ||
|
||||
open($fh, "gunzip -c $incfile.gz |") ||
|
||||
die "readWorkloadFile Couldn't open testbed file $incfile: $!";
|
||||
$filename = $incfile; # for error messages
|
||||
next;
|
||||
}
|
||||
|
||||
if (m!^</(\w+)>$!o) { # end of section
|
||||
my $end = $1;
|
||||
unless ($sparm->{"sectionTitle"} =~ /$end/i) {
|
||||
die "readWorkloadFile Mismatched section $filename: $. '$sparm->{sectionTitle}' '$end'\n";
|
||||
return 0;
|
||||
}
|
||||
($params{DEBUG}) && print "</$sparm->{sectionTitle}>\n";
|
||||
push @$plist, $sparm;
|
||||
$sparm = 0;
|
||||
next;
|
||||
}
|
||||
|
||||
if (m!^<(\w+)\s*(.*)>$!o) { # start of section
|
||||
my $sec = $1;
|
||||
my $more = $2;
|
||||
|
||||
if ($sparm) {
|
||||
die "readWorkloadFile Missing section end $filename: $. '$sparm->{sectionTitle}'\n";
|
||||
}
|
||||
if ($sec =~ /CONFIG/i) { # special case, map to existing global
|
||||
$sparm = \%params;
|
||||
} elsif ($sec =~ /DEFAULT/i) { # special case, only one DEFAULT
|
||||
if ($defaultSection) { # use existing defaultSection
|
||||
$sparm = $defaultSection;
|
||||
} else { # create a new one
|
||||
$sparm = ArrayInstance->new();
|
||||
$sparm->{"sectionTitle"} = uc $sec; # ignore case
|
||||
$sparm->{"lineList"} = ();
|
||||
$defaultSection = $sparm;
|
||||
}
|
||||
} else {
|
||||
$sparm = ArrayInstance->new();
|
||||
$sparm->{"sectionTitle"} = uc $sec; # ignore case
|
||||
$sparm->{"lineList"} = ();
|
||||
}
|
||||
$sparm->{"sectionParams"} = $more; # take newest more info
|
||||
($params{DEBUG})
|
||||
&& print "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
|
||||
next;
|
||||
}
|
||||
|
||||
# must be in a section, get parameters
|
||||
unless ($sparm) {
|
||||
die "readWorkloadFile Entry encountered outside a section $filename: $. $_\n";
|
||||
return 0;
|
||||
}
|
||||
my ($nm, $val) = split (/[\s=]+/, $_, 2);
|
||||
$nm = uc $nm; # ignore case
|
||||
($params{DEBUG}) && print " $nm = $val\n";
|
||||
if ($nm =~ /ACCOUNTFORMAT/) { # BACK COMPATIBILITY
|
||||
print "WARNING: 'accountFormat' is obsolete. Use 'addressFormat' and 'loginFormat'\n";
|
||||
$sparm->{"addressFormat"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "addressFormat $val";
|
||||
$val =~ s/@.+$//; # strip at and everything after
|
||||
$sparm->{"loginFormat"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "loginFormat $val";
|
||||
next;
|
||||
} elsif ($nm =~ /NUMACCOUNTS/) { # BACK COMPATIBILITY
|
||||
print "WARNING: 'numAccounts' is obsolete. Use 'numAddresses' and 'numLogins'\n";
|
||||
$sparm->{"numAddresses"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "numAddresses $val";
|
||||
$sparm->{"numLogins"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "numLogins $val";
|
||||
next;
|
||||
} elsif ($nm =~ /BEGINACCOUNTS/) { # BACK COMPATIBILITY
|
||||
print "WARNING: 'beginAccounts' is obsolete. Use 'firstAddress' and 'firstLogin'\n";
|
||||
$sparm->{"firstAddress"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "firstAddress $val";
|
||||
$sparm->{"firstLogin"} = $val;
|
||||
push @{$sparm->{"lineList"}}, "firstLogin $val";
|
||||
next;
|
||||
}
|
||||
push @{$sparm->{"lineList"}}, $_; # save lines in original order
|
||||
$sparm->{$nm} = $val;
|
||||
next;
|
||||
}
|
||||
close ($fh);
|
||||
$fh = pop @handles || last; # empty include stack
|
||||
$filename = $fh;
|
||||
$sparm = 0; # can only include whole sections
|
||||
}
|
||||
return 1; # success
|
||||
}
|
||||
|
||||
# Write out a workload list to a file
|
||||
# Optionally, pass in a list of sectionTitle's it should ignore
|
||||
# usage: writeWorkloadFile filename \@list [\@skipList]
|
||||
sub writeWorkloadFile {
|
||||
my $filename = shift || die "writeWorkloadFile: Missing file name";
|
||||
my $plist = shift || die "writeWorkloadFile: Missing return list";
|
||||
my $skip = shift;
|
||||
my @skipH;
|
||||
my $configSeen = 0;
|
||||
my $defaultSeen = 0;
|
||||
my @paramH;
|
||||
|
||||
if ($skip) {
|
||||
foreach $s (@$skip) { # turn list into a hash
|
||||
$skipH{(uc $s)} = $s; # fix case for index
|
||||
}
|
||||
}
|
||||
foreach $s (@workloadParameters) { # turn list into a hash
|
||||
$paramH{(uc $s)} = $s; # fix case for index
|
||||
}
|
||||
|
||||
($params{DEBUG}) && print "Writing workload to $filename.\n";
|
||||
unless (open(WORKOUT, ">$filename")) {
|
||||
die "Couldn't open testbed $filename: $!";
|
||||
}
|
||||
|
||||
foreach $sparm (@$plist) { # each hash reference in the list
|
||||
if (($skip)
|
||||
&& ($skipH{$sparm->{"sectionTitle"}})) {
|
||||
#($params{DEBUG}) &&
|
||||
#print "Skipping section $sparm->{sectionTitle}\n";
|
||||
next;
|
||||
}
|
||||
|
||||
# all CONFIG,DEFAULT sections point to the same hash, output once only
|
||||
if ($sparm->{"sectionTitle"} =~ /^CONFIG$/) {
|
||||
next if $configSeen;
|
||||
$configSeen++;
|
||||
}
|
||||
if ($sparm->{"sectionTitle"} =~ /^DEFAULT$/) {
|
||||
next if $defaultSeen;
|
||||
$defaultSeen++;
|
||||
}
|
||||
if ($sparm->{sectionParams}) { # write section with extra args
|
||||
print WORKOUT "<$sparm->{sectionTitle} $sparm->{sectionParams}>\n";
|
||||
} else {
|
||||
print WORKOUT "<$sparm->{sectionTitle}>\n";
|
||||
}
|
||||
if ($sparm->{"sectionTitle"} =~ /^(CONFIG|CLIENT)$/) {
|
||||
# for Config or Client, output the hash to get computed config
|
||||
foreach $k (sort keys %$sparm) { # output each parameter
|
||||
# skip sectionTitle and sectionParams
|
||||
($k =~ /^(sectionTitle|sectionParams|lineList)$/) && next;
|
||||
printf WORKOUT " %s\t%s\n",
|
||||
($paramH{$k}) ? $paramH{$k} : $k,
|
||||
$sparm->{$k};
|
||||
}
|
||||
} else { # write out the line list
|
||||
foreach $l (@{$sparm->{"lineList"}}) {
|
||||
print WORKOUT " $l\n";
|
||||
}
|
||||
}
|
||||
print WORKOUT "</$sparm->{sectionTitle}>\n\n";
|
||||
}
|
||||
close WORKOUT;
|
||||
}
|
||||
|
||||
# Usage: getClientFilename hostname section
|
||||
sub getClientFilename {
|
||||
my $cli = shift || die "Missing client name";
|
||||
my $section = shift || die "Missing section hash";
|
||||
return "$tmpdir/$cli-$section->{GROUP}.out"
|
||||
if ($params{USEGROUPS} && $section->{GROUP});
|
||||
return "$tmpdir/$cli.out"
|
||||
}
|
||||
|
||||
sub setConfigDefaults { # set CONFIG defaults
|
||||
# These are set after writing out the test copy to avoid clutter
|
||||
|
||||
# Path to gnuplot executable
|
||||
$params{GNUPLOT}="gnuplot/gnuplot"
|
||||
unless ($params{GNUPLOT});
|
||||
|
||||
# This is the directory the client lives in
|
||||
$params{TEMPDIR} = "/var/tmp"
|
||||
unless($params{TEMPDIR});
|
||||
|
||||
# Set default remote shell
|
||||
#$params{RSH} = "rsh"
|
||||
$params{RSH} = "ssh"
|
||||
unless($params{RSH});
|
||||
|
||||
# Set default remote copy
|
||||
#$params{RCP} = "rcp"
|
||||
$params{RCP} = "scp"
|
||||
unless($params{RCP});
|
||||
|
||||
# Size of generated gifs
|
||||
$params{CHARTHEIGHT} = 480
|
||||
unless($params{CHARTHEIGHT});
|
||||
$params{CHARTWIDTH} = 640
|
||||
unless($params{CHARTWIDTH});
|
||||
$params{CHARTPOINTS} = int (($params{CHARTWIDTH}-60)*0.8)
|
||||
unless($params{CHARTPOINTS});
|
||||
|
||||
|
||||
# The name of the remote executable
|
||||
$params{CLIENTCOMMAND} = "mailclient"
|
||||
unless ($params{CLIENTCOMMAND});
|
||||
|
||||
# Set default monitoring command
|
||||
$params{MONITORCOMMAND} = "vmstat %f"
|
||||
unless($params{MONITORCOMMAND});
|
||||
|
||||
# Set default switches to makeusers
|
||||
$params{MAKEUSERSARGS} = "-4"
|
||||
unless ($params{MAKEUSERSARGS});
|
||||
|
||||
# Figure out @protocols, this sets the report order
|
||||
@protocols = ();
|
||||
{
|
||||
my %skipH;
|
||||
foreach $s (@nonProtocolSections) { # turn list into a hash
|
||||
#print "$s ";
|
||||
$skipH{(uc $s)} = $s; # fix case for index
|
||||
}
|
||||
print "\n";
|
||||
foreach $sparm (@workload) { # each hash reference in the list
|
||||
next if ($skipH{$sparm->{"sectionTitle"}});
|
||||
|
||||
($params{DEBUG}) &&
|
||||
print "Found protocol ". $sparm->{"sectionTitle"} . "\n";
|
||||
|
||||
push @protocols, $sparm->{"sectionTitle"};
|
||||
# add to skip list so only added once
|
||||
$skipH{(uc $sparm->{"sectionTitle"})} = $sparm->{"sectionTitle"};
|
||||
}
|
||||
}
|
||||
@protocolsAll = @protocols;
|
||||
push @protocolsAll, "Total";
|
||||
|
||||
# figure out the graphs ???
|
||||
}
|
||||
|
||||
sub parseArgs { # get args
|
||||
while (@ARGV) {
|
||||
my $arg = shift(@ARGV);
|
||||
|
||||
if ($arg =~ /^-a$/i) { # was undocumented feature in 4.1
|
||||
$params{ADDGRAPHS} = shift(@ARGV); # extra graphs
|
||||
next;
|
||||
}
|
||||
if ($arg =~ /^-b$/i) {
|
||||
$params{TITLE} = shift(@ARGV); # banner
|
||||
next;
|
||||
}
|
||||
|
||||
# BACK COMPATIBILITY (everything now in the saved workload file)
|
||||
if ($arg =~ /^-c$/i) { # config file, read when encountered
|
||||
my $configFile = shift(@ARGV);
|
||||
readConfigFile ($configFile);
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-d$/i) {
|
||||
$params{DEBUG}++; # Debug
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-h$/i) { # Help
|
||||
print "Usage: -w workfile [-t time] [-r ramptime] [-l load] [-v] [-d]\n";
|
||||
print "\t[-b banner] [-n notes] [-s sysconfigfile] [-a add_graphs_file]\n";
|
||||
print "\t[-c configfile] [-m machinefile] [-z] [PARAM=value]...\n";
|
||||
|
||||
die "Usage";
|
||||
}
|
||||
|
||||
if ($arg =~ /^-l$/i) { # "load", FIX: naming conventions
|
||||
$params{CLIENTCOUNT} = shift(@ARGV); # desired client count
|
||||
next;
|
||||
}
|
||||
|
||||
# BACK COMPATIBILITY (everything now in the saved workload file)
|
||||
if ($arg =~ /^-m$/i) {
|
||||
$params{TESTBED} = shift(@ARGV); # testbed machines file
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-n$/i) {
|
||||
$params{COMMENTS} = shift(@ARGV); # notes
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-r$/i) {
|
||||
$params{RAMPTIME} = shift(@ARGV); # ramptime
|
||||
next;
|
||||
}
|
||||
if ($arg =~ /^-s$/i) {
|
||||
$params{SYSCONFIG} = shift(@ARGV); # system config html file
|
||||
next;
|
||||
}
|
||||
if ($arg =~ /^-t$/i) {
|
||||
$params{TIME} = shift(@ARGV); # test time
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-v$/i) {
|
||||
$params{VERBOSE} = 1; # verbose mode
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-w$/i) { # workload file (may occur multiple times)
|
||||
my $f = shift(@ARGV);
|
||||
readWorkloadFile ($f, \@workload) || die "Error reading workload: $@\n";
|
||||
$params{WORKLOAD} = $f;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($arg =~ /^-z$/i) {
|
||||
$params{NT} = 1; # NT mode
|
||||
next;
|
||||
}
|
||||
|
||||
# any other CONFIG parameter: FIELD=value
|
||||
if ($arg =~ /^(\w+)=(\S.*)$/) {
|
||||
my $field = uc $1;
|
||||
$params{$field} = $2;
|
||||
next;
|
||||
}
|
||||
die "Unknown argument '$arg'";
|
||||
}
|
||||
|
||||
if ($params{NT}) { # should use Cwd module
|
||||
$cwd = `cd`; # NT get current directory
|
||||
$cwd = `pwd` unless ($cwd); # in case we are really on UNIX
|
||||
} else {
|
||||
$cwd = `pwd`; # in case we are really on UNIX
|
||||
}
|
||||
chomp $cwd; # strip NL
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -1,271 +0,0 @@
|
||||
I. Format
|
||||
II. Workload Configuration Sections
|
||||
III. Report Generation Sections
|
||||
|
||||
---------
|
||||
I. Format
|
||||
---------
|
||||
|
||||
The config-file format is very free-form -- for example, this text is
|
||||
skipped as a "comment" because it doesn't look like anything else. A
|
||||
section always starts with a line ending in a colon. Everything up to
|
||||
the next section, end-of-file, or `__END__' is part of the current
|
||||
section.
|
||||
|
||||
Name/value pairs within a section are pairs starting with whitespace,
|
||||
and separated by a colon followed by whitespace. So you can write
|
||||
something like this
|
||||
|
||||
# hello there: mister foo
|
||||
|
||||
and it will be ignored. Had the '#' before the "hello" not been
|
||||
there, the attribute name would have been `hello there' and its value
|
||||
would have been `mister foo'. Leading and trailing whitespace is
|
||||
skipped, but internal whitespace is perfectly OK. Note that the
|
||||
"comment" character doesn't have to be a '#', but can be anything you
|
||||
want (except whitespace).
|
||||
|
||||
Leading whitespace also denotes continued values. So
|
||||
|
||||
foo: blah blah
|
||||
and some more words which are part of foo's value.
|
||||
|
||||
creates a variable named 'foo' with this value (including the \n) --
|
||||
"blah blah
|
||||
and some more words which are part of foo's value."
|
||||
|
||||
Finally, anything after '__END__' on a line by itself gets inserted
|
||||
literally into each .wld file. This is the place to put <monitor>
|
||||
sections.
|
||||
|
||||
--------------------------
|
||||
II. Workload Configuration
|
||||
--------------------------
|
||||
|
||||
Parameters with no default are required.
|
||||
|
||||
Messages
|
||||
--------
|
||||
|
||||
Message attributes are defined in the `message' section.
|
||||
|
||||
Parameter Default Description
|
||||
--------- ------- -----------
|
||||
size size distribution (including headers).
|
||||
recipients number of recipients
|
||||
headers ~unif(10, 30) number of headers
|
||||
line length 60 line length
|
||||
mime 0 number of MIME parts
|
||||
|
||||
Users
|
||||
-----
|
||||
|
||||
User behavior parameters are described in the `user' section.
|
||||
|
||||
Parameter Default Description
|
||||
--------- ------- -----------
|
||||
messages per day
|
||||
protocol mail read
|
||||
activity `DURATION each TIME' or `START - STOP'
|
||||
check interval how often user checks mail when active
|
||||
read messages 0 number of old msgs each user has
|
||||
read time 0 how long user takes to `read' a message
|
||||
keep 0 proportion of messages kept on server
|
||||
connection type <unlimited> `latency = X ; bandwidth = X'
|
||||
drop rate 0 proportion of connections dropped before logout
|
||||
|
||||
Delivery
|
||||
--------
|
||||
|
||||
Delivery parameters are described in the `delivery' section.
|
||||
|
||||
Parameter Default Description
|
||||
--------- ------- -----------
|
||||
messages per connection 1 messages sent per SMTP session
|
||||
percent remote 0 % mail going to remote host (sink)
|
||||
connection type <unlimited>
|
||||
fluctuation <uniform> `START - END = X % ; ...'
|
||||
|
||||
Test
|
||||
----
|
||||
|
||||
The `test' section configures the number of users, the time of day to
|
||||
be simulated, etc.
|
||||
|
||||
Parameter Default Description
|
||||
--------- ------- -----------
|
||||
start time of day to start sim
|
||||
end end time of day.
|
||||
length duration. Either length or end
|
||||
must be specified.
|
||||
users total user base
|
||||
percent active percentage of total user base active
|
||||
during test period
|
||||
messages per second messages per second to delivery for
|
||||
SMTP-only simulation. Either
|
||||
`messages per second' or `users'
|
||||
and `percent active' must be
|
||||
specified.
|
||||
comments <nothing> notes on test.
|
||||
preparer Anonymous Name to use on reports.
|
||||
date <ctime(3)>
|
||||
configuration <nothing> Configuration name for report.
|
||||
|
||||
Environment Configuration
|
||||
-------------------------
|
||||
|
||||
Several sections describe the test environment:
|
||||
|
||||
Sink
|
||||
----
|
||||
|
||||
The `sink' section describes the remote mail sink.
|
||||
|
||||
Parameter Default Description
|
||||
--------- ------- -----------
|
||||
addressFormat smuser%ld@ Like addressFormat, but used to
|
||||
generate remote addresses.
|
||||
`hostname' will be appended if it
|
||||
ends in `@'.
|
||||
hostname host on which SMTP sink lives. Used
|
||||
for remote delivery.
|
||||
|
||||
Server
|
||||
------
|
||||
|
||||
The `server' section describes the mail server to be sized:
|
||||
|
||||
Parameter Default Description
|
||||
--------- ------- -----------
|
||||
smtp port 25
|
||||
pop port 110
|
||||
imap port 143
|
||||
web port 1066
|
||||
|
||||
hostname Mail server
|
||||
|
||||
addressFormat smuser%ld@ Passed to
|
||||
sprintf(recipient, addressFormat,
|
||||
userNum, domainNum). If
|
||||
addressFormat ends in `@', `server'
|
||||
is automatically appended.
|
||||
loginFormat smuser%ld@ Same as addressFormat, but used to
|
||||
generate usernames.
|
||||
passwdFormat twang passed to sprintf(passwd, passwdFormat,
|
||||
userNum, domainNum).
|
||||
firstAddress 0 first userNum for addresses
|
||||
firstLogin 0 first userNum for logins
|
||||
smtpMailFrom $USER@$HOST sending address on test mail.
|
||||
|
||||
name Printable server name for reports.
|
||||
hardware Brief hardware description.
|
||||
software Brief software description.
|
||||
|
||||
Clients
|
||||
-------
|
||||
|
||||
The `clients' section describes test client configuration.
|
||||
|
||||
Parameter Default Description
|
||||
--------- ------- -----------
|
||||
smtp localhost client machines for SMTP
|
||||
imap localhost for IMAP
|
||||
pop localhost for POP3
|
||||
web localhost for WEBMAIL
|
||||
|
||||
rsh rsh rsh program to start remote clients
|
||||
rcp rcp rcp program to distribute files
|
||||
command mailclient program to run to start clients
|
||||
|
||||
cert file file containing SSL certificate
|
||||
key file file containing SSL key
|
||||
|
||||
Ugly Mstone details
|
||||
-------------------
|
||||
|
||||
The `mstone' section controls low-level details of how the workload
|
||||
description is translated into mstone terms. The parameters make some
|
||||
assumptions about the size of both the test clients and the server, so
|
||||
they may have to be tweaked. For small- to mid-size configurations,
|
||||
the defaults should work.
|
||||
|
||||
Parameter Default Description
|
||||
--------- ------- -----------
|
||||
preload rate 5 msgs/sec to deliver during preload.
|
||||
preload per connection 100 messages per SMTP session
|
||||
preload delivery time 750 msec expected message delivery time.
|
||||
used to control throttling.
|
||||
preload throttle 500 msec faster/slower than expected at
|
||||
which to throttle
|
||||
throttleFactor 1.1 factor by which to increase/decrease
|
||||
delivery rate when throttling
|
||||
|
||||
read rate 40 msgs/sec to read when aging old
|
||||
messages.
|
||||
read clients 5 test clients to use for aging
|
||||
read protocol (user:protocol) protocol to age messages (e.g. imap)
|
||||
|
||||
rampTime 0 test rampup time
|
||||
smtp connection time 10s
|
||||
pop user spacing 10s MULTIPOP: time between users
|
||||
pop connections per client 10 MULTIPOP: connections per client
|
||||
no event queues false use 1 thread per client
|
||||
max threads per proc 250
|
||||
clientCount 10000 artificial global clientCount
|
||||
|
||||
----------------------
|
||||
III. Report Generation
|
||||
----------------------
|
||||
|
||||
There are several additional configuration sections to provide
|
||||
additional information for sizing reports. The code is in
|
||||
`lib/{sizing,hardware}_defaults.pm'.
|
||||
|
||||
QoS Constraints
|
||||
---------------
|
||||
|
||||
Quality of Service constraints are specified in the `qos' section.
|
||||
See reports/qos.in for an example. The qos section can have any
|
||||
number of members. The name of each member is a description which
|
||||
will appear in the sizing report. The value is a block of perl code
|
||||
which should return a pair of values when evaluated in a context where
|
||||
`$run' is a reference to a hash containing data on the test run to be
|
||||
evaluated. The first value is a value corresponding to this
|
||||
constraint which will be printed in the report. The second is true if
|
||||
the run passed this constraint.
|
||||
|
||||
Hardware
|
||||
--------
|
||||
|
||||
The `machine' section describes the hardware under test. Unlike
|
||||
previous, simple sections, it containts nested values (as hash refs).
|
||||
|
||||
Parameter Description
|
||||
--------- -----------
|
||||
|
||||
processors
|
||||
speed
|
||||
cache
|
||||
|
||||
network
|
||||
|
||||
storage
|
||||
controllers
|
||||
disks
|
||||
type
|
||||
speed
|
||||
model
|
||||
timing
|
||||
OS
|
||||
parameters
|
||||
disks
|
||||
logging
|
||||
|
||||
Software
|
||||
--------
|
||||
|
||||
The `software' section describes the software under test. If multiple
|
||||
types of software are in use, multiple software sections should be
|
||||
specified. The only default parameter for software is the `name'.
|
||||
Other parameters should describe configuration information, version,
|
||||
etc.
|
||||
@@ -1,53 +0,0 @@
|
||||
test:
|
||||
start: 8 AM
|
||||
length: 1h
|
||||
users: ** Number of users here ***
|
||||
|
||||
percent active: 100
|
||||
|
||||
comments: auto-generated Corporate workload.
|
||||
|
||||
-- mail server configuration --
|
||||
|
||||
server:
|
||||
hostname: ** SERVER **
|
||||
|
||||
# defaults given below --
|
||||
# addressFormat: smuser%ld@
|
||||
# loginFormat: smuser%ld@
|
||||
# passwdFormat: twang
|
||||
|
||||
-- test client configuration --
|
||||
|
||||
clients:
|
||||
smtp: ** SMTP clients here **
|
||||
imap: ** IMAP clients here **
|
||||
|
||||
# defaults are `rsh' and `rcp'
|
||||
# rsh: ssh
|
||||
# rcp: scp
|
||||
|
||||
-- Don't edit between here and the `__END__' marker --
|
||||
|
||||
mstone:
|
||||
rampTime: 30s
|
||||
|
||||
message:
|
||||
size: ~lognormal(4k,4.5)
|
||||
recipients: ~lognormal(1,2) : [1, ]
|
||||
mime: ~binomial(0.3)
|
||||
|
||||
delivery:
|
||||
fluctuation: 8 AM - 4 PM = 90%
|
||||
|
||||
user:
|
||||
messages per day: 50
|
||||
read messages: 50
|
||||
protocol: IMAP
|
||||
check interval: ~unif(5m, 8m)
|
||||
connection type: latency = 0; bandwidth = 56k
|
||||
keep: 100%
|
||||
activity: 8 AM - 4 PM; arrival rate = ~normal(20m, 10m)
|
||||
|
||||
__END__
|
||||
# your monitor sections go here...
|
||||
@@ -1,2 +0,0 @@
|
||||
<client HOSTS=localhost>
|
||||
</client>
|
||||
@@ -1,51 +0,0 @@
|
||||
-- test size --
|
||||
|
||||
test:
|
||||
length: 90m
|
||||
users: ** Number of users here ***
|
||||
percent active: 10
|
||||
|
||||
comments: Auto-generated ISP workload.
|
||||
|
||||
-- mail server configuration --
|
||||
|
||||
server:
|
||||
hostname: ** SERVER **
|
||||
|
||||
# defaults --
|
||||
# addressFormat: smuser%ld@
|
||||
# firstAddress: 0
|
||||
# loginFormat: smuser%ld@
|
||||
# firstLogin: 0
|
||||
# passwdFormat: twang
|
||||
#
|
||||
|
||||
-- test client configuration --
|
||||
|
||||
clients:
|
||||
smtp: ** SMTP clients here **
|
||||
pop: ** POP clients go here **
|
||||
|
||||
# defaults are `rsh' and `rcp'
|
||||
# rsh: rsh
|
||||
# rcp: rcp
|
||||
|
||||
-- Do not edit between here and the `__END__' marker
|
||||
|
||||
message:
|
||||
size: ~lognormal(3k,4.5)
|
||||
recipients: ~lognormal(1,1.5) : [1, ]
|
||||
mime: 30 %
|
||||
|
||||
user:
|
||||
messages per day: 5
|
||||
read messages: 0
|
||||
protocol: POP
|
||||
check interval: ~unif(5m, 8m)
|
||||
connection type: latency = 0; bandwidth = 56k
|
||||
keep: 5%
|
||||
activity: 30 m each 24 h
|
||||
drop rate: 0.5%
|
||||
|
||||
__END__
|
||||
# other things (e.g. <monitor> sections) can go here...
|
||||
@@ -1,36 +0,0 @@
|
||||
<default>
|
||||
addressFormat smuser%ld@** DOMAIN **
|
||||
loginFormat smuser%ld@** DOMAIN **
|
||||
passwdFormat twang
|
||||
server ** SERVER **
|
||||
</default>
|
||||
|
||||
<smtp HOSTS=smtp>
|
||||
blockTime 0
|
||||
file auto
|
||||
firstAddress 0
|
||||
headers ~unif(10, 30)
|
||||
mime ~binomial(0.3)
|
||||
numAddresses 1000
|
||||
numLoops 1
|
||||
numRecips ~lognormal(1,2) : [1, ]
|
||||
size ~lognormal(4k,4.5)
|
||||
smtpMailFrom sender0@** DOMAIN **
|
||||
useEHLO 2
|
||||
portNum 2003
|
||||
</smtp>
|
||||
|
||||
<client HOSTS=localhost>
|
||||
clients 50
|
||||
group smtp
|
||||
</client>
|
||||
<config>
|
||||
comments lmtp delivery
|
||||
rampTime 0
|
||||
time 5m
|
||||
title lmtp delivery - IMAP
|
||||
useGroups 1
|
||||
</config>
|
||||
|
||||
# other things (e.g. <monitor> sections) can go here...
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<default>
|
||||
addressFormat smuser%ld@** DOMAIN **
|
||||
loginFormat smuser%ld@** DOMAIN **
|
||||
passwdFormat twang
|
||||
server ** SERVER **
|
||||
</default>
|
||||
|
||||
<smtp HOSTS=smtp>
|
||||
blockTime 0
|
||||
file auto
|
||||
firstAddress 0
|
||||
headers ~unif(10, 30)
|
||||
mime 30 %
|
||||
numAddresses 1000
|
||||
numLoops 1
|
||||
numRecips ~lognormal(1,1.5) : [1, ]
|
||||
size ~lognormal(3k,4.5)
|
||||
smtpMailFrom sender0@** DOMAIN **
|
||||
useEHLO 2
|
||||
portNum 2003
|
||||
</smtp>
|
||||
|
||||
<client HOSTS=localhost>
|
||||
clients 50
|
||||
group smtp
|
||||
</client>
|
||||
<config>
|
||||
comments lmtp delivery
|
||||
rampTime 0
|
||||
time 5m
|
||||
title lmtp delivery - POP
|
||||
useGroups 1
|
||||
</config>
|
||||
|
||||
# other things (e.g. <monitor> sections) can go here...
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
-- test size --
|
||||
|
||||
test:
|
||||
length: 90m
|
||||
users: 100
|
||||
messages per second: ** Delivery Rate **
|
||||
|
||||
comments: Auto-generated SMTP-only workload
|
||||
|
||||
-- server configuration --
|
||||
|
||||
server:
|
||||
hostname: ** SERVER **
|
||||
# addressFormat: smuser%ld@
|
||||
# firstAddress: 0
|
||||
# loginFormat: smuser%ld@
|
||||
# firstLogin: 0
|
||||
# passwdFormat: twang
|
||||
|
||||
-- client configuration --
|
||||
|
||||
clients:
|
||||
smtp: ** SMTP clients **
|
||||
|
||||
-- Do not edit between here and the `__END__' marker --
|
||||
|
||||
message:
|
||||
size: ~lognormal(3k,4.5)
|
||||
recipients: ~lognormal(1,1.5) : [1, ]
|
||||
mime: 30 %
|
||||
|
||||
__END__
|
||||
# other things (e.g. <monitor> sections) can go here...
|
||||
@@ -1,33 +0,0 @@
|
||||
-- NOT READY! --
|
||||
|
||||
test:
|
||||
length: ?
|
||||
users: ?
|
||||
percent active: ?
|
||||
|
||||
server:
|
||||
hostname: server goes here
|
||||
addressFormat: smuser%ld@
|
||||
firstAddress: 0
|
||||
loginFormat: smuser%ld@
|
||||
firstLogin: 0
|
||||
passwdFormat: twang
|
||||
|
||||
clients:
|
||||
smtp: ...
|
||||
web: ...
|
||||
|
||||
message:
|
||||
size: ~lognormal(3k,4.5)
|
||||
recipients: ~lognormal(1,1.5)
|
||||
mime: 30 %
|
||||
|
||||
user:
|
||||
messages per day: 5
|
||||
read messages: 50
|
||||
protocol: web
|
||||
check interval: 30s
|
||||
connection type: latency = 0; bandwidth = 56k
|
||||
keep: 95%
|
||||
activity: 30 m each 24h
|
||||
drop rate: 50%
|
||||
@@ -3,20 +3,6 @@
|
||||
# Define a flag for include-at-most-once
|
||||
INCLUDED_CONFIG_MK = 1
|
||||
|
||||
# Mstone features to choose at compile-time:
|
||||
# See doc/mstone_changes.html for details.
|
||||
AUTOGEN = 1 # automatic body generation
|
||||
IMAP_RAMPDOWN = 1 # ramp-down time for IMAP
|
||||
SOCK_LINESPEED = 1 # (primitive) linespeed limitation
|
||||
# SOCK_SSL = 1 # SSL/TLS and STARTTLS
|
||||
SSL_INCLUDE = /usr/include/openssl
|
||||
SSL_LIBS = /usr/lib/openssl
|
||||
|
||||
# MSG_READ_TIME = 1 # delay after message retrieval
|
||||
USE_EVENTS = 1 # use event-queue model -- less threads
|
||||
GEN_CHECKSUM = 1 # try to verify message integrity
|
||||
DYNAMIC_THROTTLE = 1 # throttle preload dynamically
|
||||
|
||||
# These normally get overridden on the command line from ../Makefile
|
||||
# This is the default build type
|
||||
BUILD_VARIANT = release
|
||||
@@ -45,7 +31,7 @@ endif
|
||||
|
||||
# setup OS specific compilers and options
|
||||
|
||||
CC = gcc
|
||||
CC = cc
|
||||
AR = ar
|
||||
INCLUDES = -I$(OBJDIR)
|
||||
REL_OS_CFLAGS = -O
|
||||
@@ -56,7 +42,7 @@ LIBS = -lm
|
||||
OBJ_SUFFIX = o
|
||||
LIB_SUFFIX = a
|
||||
EXE_SUFFIX =
|
||||
ECHO = echo
|
||||
ECHO = /bin/echo
|
||||
|
||||
ifeq ($(OS_ARCH), WINNT)
|
||||
CC = cl
|
||||
@@ -71,8 +57,8 @@ ifeq ($(OS_ARCH), WINNT)
|
||||
DLL_SUFFIX = .dll
|
||||
EXE_SUFFIX = .exe
|
||||
PERL_OS = MSWin32-x86
|
||||
# build perl manually, install to c:\perl. Then build everything else
|
||||
# cd win32 && nmake && nmake install
|
||||
# build perl manually, install to c:\perl. Then build everything else
|
||||
# cd win32 && nmake && nmake install
|
||||
PERL5_IMPORT = c:/perl/$(PERL_REV)/
|
||||
PERL_FILES = $(PERL_DIR)/Artistic
|
||||
PERL_BIN_FILES = \
|
||||
@@ -85,18 +71,18 @@ ifeq ($(OS_ARCH), IRIX64)
|
||||
ARCH = IRIX
|
||||
endif
|
||||
ifeq ($(OS_ARCH), IRIX)
|
||||
# MIPSpro Compilers: Version 7.2.1
|
||||
# MIPSpro Compilers: Version 7.2.1
|
||||
CC = /usr/bin/cc -n32
|
||||
REL_OS_CFLAGS = -fullwarn
|
||||
DBG_OS_CFLAGS = -fullwarn
|
||||
OSDEFS = -D__IRIX__ -DHAVE_SELECT_H -DHAVE_WAIT_H -DUSE_PTHREADS -DUSE_LRAND48
|
||||
LIBS = -lm -lpthread
|
||||
# OS specific flags for perl Configure
|
||||
# OS specific flags for perl Configure
|
||||
PERL_OS_CONFIGURE = -Dnm=/usr/bin/nm -Dar=/usr/bin/ar
|
||||
PERL_OS = IP27-irix
|
||||
endif
|
||||
ifeq ($(OS_ARCH), OSF1)
|
||||
# DEC C V5.6-071 on Digital UNIX V4.0(D) (Rev. 878)
|
||||
# DEC C V5.6-071 on Digital UNIX V4.0(D) (Rev. 878)
|
||||
CC = /usr/bin/cc
|
||||
REL_OS_CFLAGS = -warnprotos -verbose -newc -std1 -pthread -w0 -readonly_strings
|
||||
DBG_OS_CFLAGS = -warnprotos -verbose -newc -std1 -pthread -w0 -readonly_strings
|
||||
@@ -105,18 +91,16 @@ ifeq ($(OS_ARCH), OSF1)
|
||||
PERL_OS = alpha-dec_osf
|
||||
endif
|
||||
ifeq ($(OS_ARCH), AIX)
|
||||
CC = xlc
|
||||
# REL_OS_CFLAGS = -O -Wall
|
||||
# DBG_OS_CFLAGS = -g -Wall
|
||||
REL_OS_CFLAGS = -lpthread -qro -qroconst -qfullpath -qsrcmsg #-qflag=I:W
|
||||
DBG_OS_CFLAGS = -lpthread -qro -qroconst -g -qfullpath -qsrcmsg #-qflag=I:W
|
||||
CC = /usr/bin/xlc_r
|
||||
REL_OS_CFLAGS = -qro -qroconst -qfullpath -qsrcmsg #-qflag=I:W
|
||||
DBG_OS_CFLAGS = -qro -qroconst -g -qfullpath -qsrcmsg #-qflag=I:W
|
||||
OSDEFS = -D__AIX__ -DHAVE_SELECT_H -D_THREAD_SAFE -DUSE_PTHREADS -DUSE_LRAND48_R
|
||||
LIBS = -lm #-lpthread
|
||||
PERL_OS = aix
|
||||
endif
|
||||
ifeq ($(OS_ARCH), HP-UX)
|
||||
CC = /usr/bin/cc
|
||||
# old flags: -Ae +DA1.0 +ESlit
|
||||
# old flags: -Ae +DA1.0 +ESlit
|
||||
REL_OS_CFLAGS = +DAportable +DS2.0 -Ae +ESlit
|
||||
DBG_OS_CFLAGS = +Z +DAportable +DS2.0 -g -Ae +ESlit
|
||||
OSDEFS = -D__HPUX__ -DUSE_PTHREADS -DUSE_LRAND48
|
||||
@@ -124,96 +108,44 @@ ifeq ($(OS_ARCH), HP-UX)
|
||||
PERL_OS = PA-RISC2.0
|
||||
endif
|
||||
ifeq ($(OS_ARCH), SunOS)
|
||||
# Sun Workshop Compilers 5.0
|
||||
# Sun Workshop Compilers 5.0
|
||||
# CC = /tools/ns/workshop-5.0/bin/cc
|
||||
## REL_OS_CFLAGS = -mt -xstrconst -v -O
|
||||
## DBG_OS_CFLAGS = -mt -xstrconst -v -g -xs
|
||||
|
||||
## use GCC and install openssl
|
||||
REL_OS_CFLAGS = -O3
|
||||
DBG_OS_CFLAGS = -g
|
||||
REL_OS_CFLAGS = -mt -xstrconst -v -O
|
||||
DBG_OS_CFLAGS = -mt -xstrconst -v -g -xs
|
||||
OSDEFS = -D__SOLARIS__ -DHAVE_SELECT_H -DHAVE_WAIT_H \
|
||||
-DXP_UNIX -D_REENTRANT \
|
||||
-DUSE_PTHREADS -DUSE_GETHOSTBYNAME_R -DUSE_GETPROTOBYNAME_R -DUSE_LRAND48
|
||||
LIBS = -lm -lnsl -lsocket -lposix4 -lpthread
|
||||
|
||||
LIBS = -lm -lnsl -lsocket -lpthread
|
||||
PERL_OS = sun4-solaris
|
||||
endif
|
||||
ifeq ($(OS_ARCH), Linux)
|
||||
# Linux 2.1 kernels and above
|
||||
# Linux 2.1 kernels and above
|
||||
CC = /usr/bin/gcc # gcc 2.7.2.3
|
||||
REL_OS_CFLAGS = -O -Wall
|
||||
DBG_OS_CFLAGS = -g -Wall
|
||||
REL_OS_CFLAGS = -O -g -Wall
|
||||
DBG_OS_CFLAGS = -O1 -g -Wall
|
||||
OSDEFS = -D__LINUX__ -DHAVE_SELECT_H -DHAVE_WAIT_H -DUSE_PTHREADS -DUSE_LRAND48
|
||||
LIBS = -lm -pthread
|
||||
# Must explicitly enable interpretation of \n
|
||||
# works for /bin/echo, sh:echo, or pdksh:echo. NOT tcsh:echo
|
||||
LIBS = -lm -lpthread
|
||||
# Must explicitly enable interpretation of \n
|
||||
# works for /bin/echo, sh:echo, or pdksh:echo. NOT tcsh:echo
|
||||
ECHO = /bin/echo -e
|
||||
PERL_OS = i686-linux
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH), FreeBSD)
|
||||
CC = gcc # gcc 2.7.2.3
|
||||
REL_OS_CFLAGS = -O -Wall
|
||||
DBG_OS_CFLAGS = -g -Wall
|
||||
OSDEFS = -D__FREEBSD__ -DHAVE_SELECT_H -DUSE_PTHREADS -DUSE_LRAND48
|
||||
LIBS = -lm -pthread
|
||||
# Must explicitly enable interpretation of \n
|
||||
# works for /bin/echo, sh:echo, or pdksh:echo. NOT tcsh:echo
|
||||
ECHO = /bin/echo -e
|
||||
PERL_OS = i686-freebsd
|
||||
endif
|
||||
|
||||
# pull in any OS extra config, if available
|
||||
-include $(topsrcdir)/config/$(OS_ARCH)/config.mk
|
||||
|
||||
ifeq ($(BUILD_TYPE), DEBUG)
|
||||
OS_CFLAGS = $(DBG_OS_CFLAGS) -D_DEBUG -DDIRECT_OUT
|
||||
OS_CFLAGS = $(DBG_OS_CFLAGS) -D_DEBUG
|
||||
OS_LINKFLAGS = $(DBG_OS_LINKFLAGS)
|
||||
else
|
||||
OS_CFLAGS = $(REL_OS_CFLAGS)
|
||||
OS_LINKFLAGS = $(REL_OS_CFLAGS)
|
||||
endif
|
||||
|
||||
# Features:
|
||||
# FEATURE_DEFINES=-DDIRECT_OUT
|
||||
# FEATURE_LIBS=
|
||||
# FEATURE_INCLUDES=
|
||||
ifdef SOCK_SSL
|
||||
FEATURE_DEFINES += -DSOCK_SSL
|
||||
FEATURE_LIBS += -L$(SSL_LIBS) -lssl -lcrypto
|
||||
FEATURE_INCLUDES += -I$(SSL_INCLUDE)
|
||||
endif
|
||||
ifdef AUTOGEN
|
||||
FEATURE_DEFINES += -DAUTOGEN
|
||||
ifdef GEN_CHECKSUM
|
||||
FEATURE_DEFINES += -DGEN_CHECKSUM=1
|
||||
FEATURE_SRCS += checksum.c md5.c
|
||||
endif
|
||||
endif
|
||||
ifdef IMAP_RAMPDOWN
|
||||
FEATURE_DEFINES += -DIMAP_RAMPDOWN
|
||||
endif
|
||||
ifdef DYNAMIC_THROTTLE
|
||||
FEATURE_DEFINES += -DDYNAMIC_THROTTLE
|
||||
endif
|
||||
ifdef SOCK_LINESPEED
|
||||
FEATURE_DEFINES += -DSOCK_LINESPEED
|
||||
endif
|
||||
ifdef MSG_READ_TIME
|
||||
FEATURE_DEFINES += -DMSG_READ_TIME
|
||||
endif
|
||||
ifdef USE_EVENTS
|
||||
FEATURE_DEFINES += -DUSE_EVENTS
|
||||
FEATURE_SRCS += event.c
|
||||
endif
|
||||
|
||||
CPPFLAGS =
|
||||
CFLAGS = $(OS_CFLAGS)
|
||||
###DEFINES = -DHAVE_CONFIG_H $(OSDEFS)
|
||||
DEFINES = $(OSDEFS) $(FEATURE_DEFINES)
|
||||
LIBS += $(FEATURE_LIBS)
|
||||
INCLUDES += $(FEATURE_INCLUDES)
|
||||
DEFINES = $(OSDEFS)
|
||||
LDFLAGS =
|
||||
|
||||
CP = cp
|
||||
|
||||
@@ -123,7 +123,7 @@ Mailstone Utility
|
||||
This document describes how to use Mailstone 4.1 for capacity planning and testing on Netscape Messaging Server and other mail servers. </P></A>
|
||||
<A NAME="1017268">
|
||||
This document contains the following sections: </P></A>
|
||||
<ul><P><A NAME="1011972"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="#1011979">About the Mailstone Utility</a> </FONT></LI></A><A NAME="1036539"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="#1022848">Installing Mailstone</a> </FONT></LI></A><BR><A NAME="1036546"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="#1024558">Setting Up Mailstone Tests</a> </FONT></LI></A><BR><A NAME="1037932"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="#1061767">Synchronizing Client Machines</a> </FONT></LI></A><BR><A NAME="1036553"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="#1049983">Running Mailstone</a> </FONT></LI></A><BR><A NAME="1036567"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="#1061822">Reviewing Test Results</a> </FONT></LI></A><BR><A NAME="1062165"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="#1061888">Detailed Protocol Test Steps</a></FONT></LI></A><BR><A NAME="1036574"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="#1043075">Removing Mailstone</a> </FONT></LI></A><BR></ul><BR></TD></TR><TR> <TD BGCOLOR="#9999CC"><A HREF="#top"><IMG SRC="up.gif" BORDER=0></A><A NAME="About the Mailstone Utility"></A><A NAME="1011979"><FONT FACE="Palatino, Serif" SIZE="+2" COLOR="white"> <B>About the Mailstone Utility</B></FONT></A></TD></TR><TR><TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" Size=-1><A NAME="1011982">
|
||||
<ul><P><A NAME="1011972"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="stone.htm#1011979">About the Mailstone Utility</a> </FONT></LI></A><A NAME="1036539"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="stone.htm#1022848">Installing Mailstone</a> </FONT></LI></A><BR><A NAME="1036546"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="stone.htm#1024558">Setting Up Mailstone Tests</a> </FONT></LI></A><BR><A NAME="1037932"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="stone.htm#1061767">Synchronizing Client Machines</a> </FONT></LI></A><BR><A NAME="1036553"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="stone.htm#1049983">Running Mailstone</a> </FONT></LI></A><BR><A NAME="1036567"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="stone.htm#1061822">Reviewing Test Results</a> </FONT></LI></A><BR><A NAME="1062165"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="stone.htm#1061888">Detailed Protocol Test Steps</a></FONT></LI></A><BR><A NAME="1036574"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><a href="stone.htm#1043075">Removing Mailstone</a> </FONT></LI></A><BR></ul><BR></TD></TR><TR> <TD BGCOLOR="#9999CC"><A HREF="#top"><IMG SRC="up.gif" BORDER=0></A><A NAME="About the Mailstone Utility"></A><A NAME="1011979"><FONT FACE="Palatino, Serif" SIZE="+2" COLOR="white"> <B>About the Mailstone Utility</B></FONT></A></TD></TR><TR><TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" Size=-1><A NAME="1011982">
|
||||
The Mailstone utility is a stress-testing tool that system administrators can use to determine Netscape Messaging Server capacity by testing how the server performs under load. You can use Mailstone on all Unix platforms supported by Netscape Messaging Server and also on Windows NT. </P></A>
|
||||
<A NAME="1023527">
|
||||
Mailstone can also be used to similarly test and compare other mail servers that support SMTP, POP, and IMAP protocols. </P></A>
|
||||
@@ -136,7 +136,7 @@ Mailstone measures both throughput and response time of the mail server being te
|
||||
<A NAME="1023254">
|
||||
Mailstone is run on a client machine (referred to as <em>testmaster</em> in these instructions). </P></A>
|
||||
<ul><P><A NAME="1030719"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif">In Unix environments, the test can be configured to include additional client machines (referred to as <I>testclients</I> in these instructions). These additional clients can be any supported Unix machine. The testmaster machine can also function as a testclient machine.</FONT></LI></A><P><A NAME="1030720"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif">In NT environments, Mailstone runs only on the single testmaster machine which acts as both testmaster and testclient. </FONT></LI></A></ul><A NAME="1030721">
|
||||
The Mailstone testbed consists of the testmaster machine, any testclient machines, the Messaging Server to be tested, plus the network configuration and Directory Server. (See <a href="#1044600">Figure 0.1</a>.) </P></A>
|
||||
The Mailstone testbed consists of the testmaster machine, any testclient machines, the Messaging Server to be tested, plus the network configuration and Directory Server. (See <a href="stone.htm#1044600">Figure 0.1</a>.) </P></A>
|
||||
<A NAME="1044600">
|
||||
<P><B>Figure 0.1 Mailstone Testbed (Unix environment)<p><img src="stone01.gif">
|
||||
</B></P>
|
||||
@@ -159,7 +159,7 @@ When Mailstone is run on the testmaster machine using the <FONT FACE="courier, c
|
||||
<BR></TD></TR><TR> <TD BGCOLOR="#9999CC"><A HREF="#top"><IMG SRC="up.gif" BORDER=0></A><A NAME="Installing Mailstone"></A><A NAME="1022848"><FONT FACE="Palatino, Serif" SIZE="+2" COLOR="white"> <B>Installing Mailstone</B></FONT></A></TD></TR><TR><TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" Size=-1><A NAME="1038215">
|
||||
You can install Mailstone at the same time as Messaging Server by choosing Mailstone as one of the Messaging Server components to be installed. See your Messaging Server installation instructions for details on how to do this. The Mailstone software that is installed at the same time as Messaging Server is a version for the same operating system used by Messaging Server. </P></A>
|
||||
<A NAME="1038216">
|
||||
The instructions in this section describe how to install an all-platforms version of Mailstone separate from a Messaging Server installation. This Mailstone version can be used to test Messaging Server or any other Mailstone-compatible email server. (If you initially install Mailstone as part of Messaging Server installation and later want to install the all-platforms version of Mailstone, see <a href="#1038301">Reinstalling Mailstone</a>.)</P></A>
|
||||
The instructions in this section describe how to install an all-platforms version of Mailstone separate from a Messaging Server installation. This Mailstone version can be used to test Messaging Server or any other Mailstone-compatible email server. (If you initially install Mailstone as part of Messaging Server installation and later want to install the all-platforms version of Mailstone, see <a href="stone.htm#1038301">Reinstalling Mailstone</a>.)</P></A>
|
||||
<A NAME="1023635">
|
||||
To transfer, extract, and install the all-platforms version of the Mailstone archive files follow these steps:</P></A>
|
||||
<ol>
|
||||
@@ -214,11 +214,11 @@ The extraction process creates the required Mailstone files and places them in a
|
||||
<FONT FACE="courier, courier new, monospace">mailstone</FONT> directory and associated subdirectories.
|
||||
|
||||
</A></P><P><A NAME="1024217">
|
||||
See <a href="#1091108">Table 0.2</a> for a description of the main Mailstone files.
|
||||
See <a href="stone.htm#1091108">Table 0.2</a> for a description of the main Mailstone files.
|
||||
|
||||
</A></P></ol>
|
||||
<A NAME="1023544">
|
||||
Once Mailstone is installed, you set up (configure) each test as described in <a href="#1024558">Setting Up Mailstone Tests</a> and then run the <FONT FACE="courier, courier new, monospace">mstone</FONT> program as described in <a href="#1061767">Synchronizing Client Machines</a>. </P></A>
|
||||
Once Mailstone is installed, you set up (configure) each test as described in <a href="stone.htm#1024558">Setting Up Mailstone Tests</a> and then run the <FONT FACE="courier, courier new, monospace">mstone</FONT> program as described in <a href="stone.htm#1061767">Synchronizing Client Machines</a>. </P></A>
|
||||
<A NAME="Reinstalling Mailstone"></A><A NAME="1038301"><FONT FACE="Palatino, Serif" SIZE="+2" COLOR="black"> <B>
|
||||
Reinstalling Mailstone</B></FONT></A><P>
|
||||
<A NAME="1038302">
|
||||
@@ -286,7 +286,7 @@ numbering will be used in the password).
|
||||
</a>
|
||||
|
||||
<P><a name="1091567">
|
||||
<B><FONT FACE="ARIAL"><LI></FONT></B>Answer <FONT FACE="courier, courier new, monospace">yes</FONT> to view the new configuration file. Make any additional changes to <FONT FACE="courier, courier new, monospace">conf/general.html </FONT>with a text editor. See <a href="#1026185">Configuring Test Execution</a> for details about adding clients and controlling test execution. To re-run the simple configuration editor, run <FONT FACE="courier, courier new, monospace">setup config</FONT>.</LI>
|
||||
<B><FONT FACE="ARIAL"><LI></FONT></B>Answer <FONT FACE="courier, courier new, monospace">yes</FONT> to view the new configuration file. Make any additional changes to <FONT FACE="courier, courier new, monospace">conf/general.html </FONT>with a text editor. See <a href="stone.htm#1026185">Configuring Test Execution</a> for details about adding clients and controlling test execution. To re-run the simple configuration editor, run <FONT FACE="courier, courier new, monospace">setup config</FONT>.</LI>
|
||||
</a>
|
||||
|
||||
<P><a name="1048808">
|
||||
@@ -294,7 +294,7 @@ numbering will be used in the password).
|
||||
</a>
|
||||
|
||||
<P><A NAME="1048811">
|
||||
By default, this file is named <FONT FACE="courier, courier new, monospace">conf/general.html</FONT>. See <a href="#1026893">System Data File
|
||||
By default, this file is named <FONT FACE="courier, courier new, monospace">conf/general.html</FONT>. See <a href="stone.htm#1026893">System Data File
|
||||
(general.html)</a>.
|
||||
|
||||
</A></P><P><a name="1044171">
|
||||
@@ -311,7 +311,7 @@ you must still run <FONT FACE="courier, courier new, monospace">setup</FONT> bec
|
||||
machine.)
|
||||
|
||||
</A></P><P><a name="1044150">
|
||||
<B><FONT FACE="ARIAL"><LI></FONT></B>Important. If you are using more than one testclient machine, run <FONT FACE="courier, courier new, monospace">checktime</FONT> as described in <a href="#1061767">Synchronizing Client Machines</a> to verify that the system clocks are within 2 seconds of each other.</LI>
|
||||
<B><FONT FACE="ARIAL"><LI></FONT></B>Important. If you are using more than one testclient machine, run <FONT FACE="courier, courier new, monospace">checktime</FONT> as described in <a href="stone.htm#1061767">Synchronizing Client Machines</a> to verify that the system clocks are within 2 seconds of each other.</LI>
|
||||
</a>
|
||||
|
||||
</ol>
|
||||
@@ -323,7 +323,7 @@ Establishing the Test User Base</B></FONT></A><P>
|
||||
In order to test a messaging server, you need to create a set of test users. During set up, you created an LDIF file that will create these users in the Directory Server used by Netscape Messaging Server. If you are testing another kind of mail server, you will have to use other means to create these accounts.</P></A>
|
||||
<A NAME="1049331">
|
||||
You then add the test LDIF file's entries to your directory. You can use either of the following to update the LDAP Directory from the <FONT FACE="courier, courier new, monospace">conf/mailhost.ldif</FONT> file:</P></A>
|
||||
<ul><P><A NAME="1049332"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Database Manager</B>. The Netscape Directory Server provides a Database Manager that can be used to update the LDAP Directory as described in <a href="#1049342">Adding Test Users with Database Manager</a>. </FONT></LI></A><P><A NAME="1049336"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>ldapmodify</B>. You can also use the <FONT FACE="courier, courier new, monospace">ldapmodify</FONT> command-line utility to update the LDAP Directory as described in <a href="#1070712">Adding Test Users with ldapmodify</a>.</FONT></LI></A><P><A NAME="1049504"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Edit the database</B>. (Experts only) You can export the current database, append the new entries, and then import the new version. This is the fastest method and makes adding millions of users practical.</FONT></LI></A></ul><A NAME="1049340">
|
||||
<ul><P><A NAME="1049332"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Database Manager</B>. The Netscape Directory Server provides a Database Manager that can be used to update the LDAP Directory as described in <a href="stone.htm#1049342">Adding Test Users with Database Manager</a>. </FONT></LI></A><P><A NAME="1049336"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>ldapmodify</B>. You can also use the <FONT FACE="courier, courier new, monospace">ldapmodify</FONT> command-line utility to update the LDAP Directory as described in <a href="stone.htm#1070712">Adding Test Users with ldapmodify</a>.</FONT></LI></A><P><A NAME="1049504"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Edit the database</B>. (Experts only) You can export the current database, append the new entries, and then import the new version. This is the fastest method and makes adding millions of users practical.</FONT></LI></A></ul><A NAME="1049340">
|
||||
<B>Caution:</B> You should backup the Directory Server before making any changes. </P></A>
|
||||
<A NAME="Adding Test Users with Database Manager"></A><A NAME="1049342"><FONT FACE="Palatino, Serif" SIZE="-1" COLOR="black"> <B>
|
||||
Adding Test Users with Database Manager</B></FONT></A><P>
|
||||
@@ -385,7 +385,7 @@ not to overwrite any other entries.
|
||||
|
||||
</ol>
|
||||
<A NAME="1070734">
|
||||
See <a href="#1048564">Appendix</a> for steps for adding users under Directory 3.x or using <FONT FACE="courier, courier new, monospace">ldapmodify</FONT>.</P></A>
|
||||
See <a href="stone.htm#1048564">Appendix</a> for steps for adding users under Directory 3.x or using <FONT FACE="courier, courier new, monospace">ldapmodify</FONT>.</P></A>
|
||||
<A NAME="Synchronizing Client Machines"></A><A NAME="1061767"><FONT FACE="Palatino, Serif" SIZE="+2" COLOR="black"> <B>
|
||||
Synchronizing Client Machines</B></FONT></A><P>
|
||||
<A NAME="1061768">
|
||||
@@ -410,7 +410,7 @@ To run a Mailstone test:</P></A>
|
||||
</a>
|
||||
|
||||
<P><a name="1049988">
|
||||
<B><FONT FACE="ARIAL"><LI></FONT></B>If you have additional testclient machines in a Unix environment, synchronize them as described in <a href="#1061767">Synchronizing Client Machines</a>.</LI>
|
||||
<B><FONT FACE="ARIAL"><LI></FONT></B>If you have additional testclient machines in a Unix environment, synchronize them as described in <a href="stone.htm#1061767">Synchronizing Client Machines</a>.</LI>
|
||||
</a>
|
||||
|
||||
<P><a name="1049997">
|
||||
@@ -436,7 +436,7 @@ You can specify command line options as needed. Running <FONT FACE="courier, cou
|
||||
<A NAME="1050153">
|
||||
Options specified on the command line override any corresponding configuration parameters in a configuration file. For example, if the configuration file sets the test run time to two hours, but you only want to make a brief trial run of 10 minutes to make sure that the configuration is correct, you would enter this:</P></A>
|
||||
<pre><A NAME="1050003"><FONT FACE="courier, courier new, monospace">mstone popsmtp -t 10m</FONT></A><P></pre><A NAME="1050007">
|
||||
<a href="#1050011">Table 0.1</a> describes the command line options you can use with the <FONT FACE="courier, courier new, monospace">mstone</FONT> command. </P></A>
|
||||
<a href="stone.htm#1050011">Table 0.1</a> describes the command line options you can use with the <FONT FACE="courier, courier new, monospace">mstone</FONT> command. </P></A>
|
||||
<A NAME="1050070">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="mstone command line options
|
||||
"></A><A NAME="1050011"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.1 mstone command line options
|
||||
@@ -576,7 +576,7 @@ Mailstone displays the results of a test run as an HTML page named <FONT FACE="c
|
||||
<A NAME="1061826">
|
||||
An HTML-formatted index of all test runs is created and maintained in the <FONT FACE="courier, courier new, monospace">results/index.html</FONT> file. This file contains live links to the <FONT FACE="courier, courier new, monospace">results.html</FONT> files from every test run. </P></A>
|
||||
<A NAME="1061830">
|
||||
The top portion of a typical results file is shown in <a href="#1061835">Figure 0.2</a>. (Your results will vary depending on how you configured your test run.)</P></A>
|
||||
The top portion of a typical results file is shown in <a href="stone.htm#1061835">Figure 0.2</a>. (Your results will vary depending on how you configured your test run.)</P></A>
|
||||
<A NAME="1061835">
|
||||
<P><B>Figure 0.2 Example Mailstone test result page (top portion)<p><img src="stone02.gif">
|
||||
</B></P>
|
||||
@@ -595,7 +595,7 @@ The number of successful operations is <B>tries</B> minus <B>errors</B>.</P></A>
|
||||
Note that actual precision of the time values depends on the precision of the system clock and on statistical sampling. The times are displayed in seconds unless other units are shown.</P></A>
|
||||
<A NAME="About the Report Rows"></A><A NAME="1070800"><FONT FACE="Palatino, Serif" SIZE="+1" COLOR="black"> <B>
|
||||
About the Report Rows</B></FONT></A><P><A NAME="1070760">
|
||||
Each row in the report is a timer for a specific aspect of the protocol test. The one exception is "Total", which is a sum of the other timers. Details of how each timer is used in each protocol are found in <a href="#1061888">Detailed Protocol Test Steps</a>. Here is the current list of possible timers: </P></A>
|
||||
Each row in the report is a timer for a specific aspect of the protocol test. The one exception is "Total", which is a sum of the other timers. Details of how each timer is used in each protocol are found in <a href="stone.htm#1061888">Detailed Protocol Test Steps</a>. Here is the current list of possible timers: </P></A>
|
||||
<ul><P><A NAME="1087448"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Total</B>. The total timer contains a sum of all the other timers.</FONT></LI></A><P><A NAME="1070761"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Connect</B>. The connect timer is the establishment of the TCP connection to the server. </FONT></LI></A><P><A NAME="1070762"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Banner</B>. The banner timer includes the message sent from the server when a connection is established.</FONT></LI></A><P><A NAME="1070763"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Login</B>. The login timer includes sending the user ID and password and having it verified.</FONT></LI></A><P><A NAME="1070764"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Command</B>. The command timer records all other protocol exchanges between the client and server.</FONT></LI></A><P><A NAME="1070765"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Submit</B>. The submit timer records message data sent to the server.</FONT></LI></A><P><A NAME="1070766"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Retrieve</B>. The retrieve timer records messages received from the server.</FONT></LI></A><P><A NAME="1070767"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Headers</B>. The headers timer records non-message HTML pages received from the server.</FONT></LI></A><P><A NAME="1070768"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Logout</B>. The logout timer records normally closed connections.</FONT></LI></A><P><A NAME="1070769"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Idle</B>. The idle timer records time that the client spent sleeping between requests to the server.</FONT></LI></A></ul><A NAME="1070771">
|
||||
Some stages may be bypasses depending on the protocol and workload. For example, the SMTP protocol will only do a "Login" if <FONT FACE="courier, courier new, monospace">useEHLO</FONT> and <FONT FACE="courier, courier new, monospace">useAuthLogin</FONT> are enabled and the server supports AUTHLOGIN.</P></A>
|
||||
<A NAME="1062123">
|
||||
@@ -613,7 +613,7 @@ If advanced customization of test reporting is needed, import the <FONT FACE="co
|
||||
Further graphing can be done by importing the <FONT FACE="courier, courier new, monospace">results/</FONT>timestamp<FONT FACE="courier, courier new, monospace">/time-*.csv</FONT> files into a spreadsheet. Each file contains the sum of all client's timers over the duration of the test for one protocol.</P></A>
|
||||
<A NAME="Additional Details"></A><A NAME="1070847"><FONT FACE="Palatino, Serif" SIZE="+1" COLOR="black"> <B>
|
||||
Additional Details</B></FONT></A><P><A NAME="1070779">
|
||||
At the end of the <FONT FACE="courier, courier new, monospace">results.html</FONT> file under the heading "Details" is a description of the test environment. This is the text you specified in the system data file (<FONT FACE="courier, courier new, monospace">conf/general.html</FONT>). This allows you to capture all the configuration that is beyond the scope of Mailstone, but critical to what you are testing. Typical information to document includes: software version, operating system version, hardware capacities, network configuration, disk organization, caching configuration, and so on. A simple description is shown in <a href="#1070787">Figure 0.3</a>.</P></A>
|
||||
At the end of the <FONT FACE="courier, courier new, monospace">results.html</FONT> file under the heading "Details" is a description of the test environment. This is the text you specified in the system data file (<FONT FACE="courier, courier new, monospace">conf/general.html</FONT>). This allows you to capture all the configuration that is beyond the scope of Mailstone, but critical to what you are testing. Typical information to document includes: software version, operating system version, hardware capacities, network configuration, disk organization, caching configuration, and so on. A simple description is shown in <a href="stone.htm#1070787">Figure 0.3</a>.</P></A>
|
||||
<A NAME="1070787">
|
||||
<P><B>Figure 0.3 Example Mailstone test results page (test description)<p><img src="stone03.gif">
|
||||
</B></P>
|
||||
@@ -622,7 +622,7 @@ Test and Configuration Files</B></FONT></A><P>
|
||||
<A NAME="1049847">
|
||||
Mailstone files are stored in a directory named <FONT FACE="courier, courier new, monospace">mailstone</FONT> with several subdirectories. All programs must be run from the <FONT FACE="courier, courier new, monospace">mailstone</FONT> directory. These directories are created when the Mailstone files are extracted with <FONT FACE="courier, courier new, monospace">tar</FONT> (Unix) or are <FONT FACE="courier, courier new, monospace">unzip</FONT> (NT). File names are the same for both Unix and NT platforms, except that in some cases NT files have filename extensions such as <FONT FACE="courier, courier new, monospace">.exe</FONT> or <FONT FACE="courier, courier new, monospace">.bat</FONT>. </P></A>
|
||||
<A NAME="1049851">
|
||||
The main Mailstone files are listed in <a href="#1091108">Table 0.2</a> (ancillary files are not listed). </P></A>
|
||||
The main Mailstone files are listed in <a href="stone.htm#1091108">Table 0.2</a> (ancillary files are not listed). </P></A>
|
||||
<A NAME="1090940">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="Important Mailstone Files
|
||||
"></A><A NAME="1091108"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.2 Important Mailstone Files
|
||||
@@ -630,7 +630,7 @@ The main Mailstone files are listed in <a href="#1091108">Table 0.2</a> (ancilla
|
||||
<tr><td valign=top><A NAME="1091116"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1><FONT FACE="courier, courier new, monospace">mstone
|
||||
</FONT></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1091118"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>The command script that you run to perform a Mailstone test
|
||||
as described in <a href="#1061767">Synchronizing Client Machines</a>.
|
||||
as described in <a href="stone.htm#1061767">Synchronizing Client Machines</a>.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
|
||||
@@ -668,7 +668,7 @@ Mailstone.
|
||||
the correct version of Mailstone software and the specified test
|
||||
messages to the <FONT FACE="courier, courier new, monospace">/var/tmp</FONT> directories in Unix environments
|
||||
or the <FONT FACE="courier, courier new, monospace">%TEMP%</FONT> directory in NT environments. See
|
||||
<a href="#1061767">Synchronizing Client Machines</a>.
|
||||
<a href="stone.htm#1061767">Synchronizing Client Machines</a>.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
|
||||
@@ -676,7 +676,7 @@ or the <FONT FACE="courier, courier new, monospace">%TEMP%</FONT> directory in N
|
||||
</FONT></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1091148"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>A utility that checks the current system time on all machines
|
||||
that are part of the test. (Unix environments only). See
|
||||
<a href="#1061767">Synchronizing Client Machines</a>.
|
||||
<a href="stone.htm#1061767">Synchronizing Client Machines</a>.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
|
||||
@@ -684,7 +684,7 @@ that are part of the test. (Unix environments only). See
|
||||
</FONT></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1091155"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>A utility the synchronizes the system time on all machines that
|
||||
are part of the test. (Unix environments only). See
|
||||
<a href="#1061767">Synchronizing Client Machines</a>.
|
||||
<a href="stone.htm#1061767">Synchronizing Client Machines</a>.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
|
||||
@@ -692,14 +692,14 @@ are part of the test. (Unix environments only). See
|
||||
</FONT></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1091162"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>The system data file that describes the system configuration.
|
||||
The contents of <FONT FACE="courier, courier new, monospace">general.html</FONT> are appended to the test
|
||||
result output. See <a href="#1026893">System Data File (general.html)</a>.
|
||||
result output. See <a href="stone.htm#1026893">System Data File (general.html)</a>.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
|
||||
<tr><td valign=top><A NAME="1091167"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1><FONT FACE="courier, courier new, monospace">conf/general.wld
|
||||
</FONT></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1091169"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>The general configuration file you use to specify configuration
|
||||
parameters for the test as a whole. See <a href="#1035278">General Configuration
|
||||
parameters for the test as a whole. See <a href="stone.htm#1035278">General Configuration
|
||||
File (general.wld)</a>.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
@@ -707,7 +707,7 @@ File (general.wld)</a>.
|
||||
<tr><td valign=top><A NAME="1091186"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1><FONT FACE="courier, courier new, monospace">conf/*.wld
|
||||
</FONT></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1091188"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>The workload configuration files you use to specify tests. See
|
||||
<a href="#1025634">Workload Configuration File (testname.wld)</a>.
|
||||
<a href="stone.htm#1025634">Workload Configuration File (testname.wld)</a>.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
|
||||
@@ -720,7 +720,7 @@ File (general.wld)</a>.
|
||||
<tr><td valign=top><A NAME="1091197"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1><FONT FACE="courier, courier new, monospace">data/*.msg
|
||||
</FONT></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1091199"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>The "filler" message bodies that Mailstone uses when it sends
|
||||
messages during testing. See <a href="#1071397">Test Messages</a>.
|
||||
messages during testing. See <a href="stone.htm#1071397">Test Messages</a>.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
|
||||
@@ -742,7 +742,7 @@ All the details of test execution are performed on the `testmaster' machine. The
|
||||
Configuration files can include other configuration files using <br><FONT FACE="courier, courier new, monospace"><include conf/</FONT><I><FONT FACE="courier, courier new, monospace">filename</FONT></I><FONT FACE="courier, courier new, monospace">.wld></FONT>. This allows all the general configuration information to be kept in one file and not to have to be repeated in each test workload. A section must be completely contained in a single file.</P></A>
|
||||
<A NAME="1030837">
|
||||
There are different kinds of configuration files:</P></A>
|
||||
<ul><P><A NAME="1030883"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>General</B>. The general configuration file specifies parameters that apply to all your Mailstone tests. Each test includes <FONT FACE="courier, courier new, monospace">conf/general.wld</FONT> to define common parameters. The mailstone utilities <FONT FACE="courier, courier new, monospace">setup</FONT>, <FONT FACE="courier, courier new, monospace">cleanup</FONT>, <FONT FACE="courier, courier new, monospace">checktime</FONT>, and <FONT FACE="courier, courier new, monospace">timesync</FONT> also read <FONT FACE="courier, courier new, monospace">conf/general.wld</FONT> for test client machines and test account information. See <a href="#1035278">General Configuration File (general.wld)</a>. </FONT></LI></A><P><A NAME="1031229"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Workload</B>. The workload configuration file specifies the protocols to be tested, the attributes for each protocol, and the test messages to be used. By default, workload configuration files use the filename extension <FONT FACE="courier, courier new, monospace">.wld</FONT>. Mailstone provides sample workload files for different kinds of tests: <FONT FACE="courier, courier new, monospace">imap.wld</FONT>, <FONT FACE="courier, courier new, monospace">pop.wld</FONT>, <FONT FACE="courier, courier new, monospace">smtp.wld</FONT>, <FONT FACE="courier, courier new, monospace">popimapsmtp.wld</FONT>, and <FONT FACE="courier, courier new, monospace">popsmtp.wld</FONT>. See <a href="#1025634">Workload Configuration File (testname.wld)</a>. </FONT></LI></A><P><A NAME="1048879"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>System Data</B>. The system data file specifies any information that you wish to have appended to test results. By default, this file is named <FONT FACE="courier, courier new, monospace">general.html</FONT>. See <a href="#1026893">System Data File (general.html)</a>. </FONT></LI></A></ul><A NAME="Specifying Times in Configuration Files"></A><A NAME="1040549"><FONT FACE="Palatino, Serif" SIZE="-1" COLOR="black"> <B>
|
||||
<ul><P><A NAME="1030883"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>General</B>. The general configuration file specifies parameters that apply to all your Mailstone tests. Each test includes <FONT FACE="courier, courier new, monospace">conf/general.wld</FONT> to define common parameters. The mailstone utilities <FONT FACE="courier, courier new, monospace">setup</FONT>, <FONT FACE="courier, courier new, monospace">cleanup</FONT>, <FONT FACE="courier, courier new, monospace">checktime</FONT>, and <FONT FACE="courier, courier new, monospace">timesync</FONT> also read <FONT FACE="courier, courier new, monospace">conf/general.wld</FONT> for test client machines and test account information. See <a href="stone.htm#1035278">General Configuration File (general.wld)</a>. </FONT></LI></A><P><A NAME="1031229"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Workload</B>. The workload configuration file specifies the protocols to be tested, the attributes for each protocol, and the test messages to be used. By default, workload configuration files use the filename extension <FONT FACE="courier, courier new, monospace">.wld</FONT>. Mailstone provides sample workload files for different kinds of tests: <FONT FACE="courier, courier new, monospace">imap.wld</FONT>, <FONT FACE="courier, courier new, monospace">pop.wld</FONT>, <FONT FACE="courier, courier new, monospace">smtp.wld</FONT>, <FONT FACE="courier, courier new, monospace">popimapsmtp.wld</FONT>, and <FONT FACE="courier, courier new, monospace">popsmtp.wld</FONT>. See <a href="stone.htm#1025634">Workload Configuration File (testname.wld)</a>. </FONT></LI></A><P><A NAME="1048879"><LI><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>System Data</B>. The system data file specifies any information that you wish to have appended to test results. By default, this file is named <FONT FACE="courier, courier new, monospace">general.html</FONT>. See <a href="stone.htm#1026893">System Data File (general.html)</a>. </FONT></LI></A></ul><A NAME="Specifying Times in Configuration Files"></A><A NAME="1040549"><FONT FACE="Palatino, Serif" SIZE="-1" COLOR="black"> <B>
|
||||
Specifying Times in Configuration Files</B></FONT></A><P>
|
||||
<A NAME="1040550">
|
||||
Times are specified in configuration commands (or on the command line) by a number followed by one of these time unit designations:</P></A>
|
||||
@@ -783,7 +783,7 @@ There is a general CONFIG section in <FONT FACE="courier, courier new, monospace
|
||||
<A NAME="1070898">
|
||||
Every parameter in CONFIG can be overridden from the command line using either a predefined switch, or an <I><FONT FACE="courier, courier new, monospace">ATTRIBUTE=value</FONT></I> definition. For example: <FONT FACE="courier, courier new, monospace">mstone pop -b `Initialize store'</FONT> would run the pop test with a title (banner) of `Initialize store'.</P></A>
|
||||
<A NAME="1070909">
|
||||
<a href="#1070913">Table 0.3</a> describes the various attributes you can use in the CONFIG section. </P></A>
|
||||
<a href="stone.htm#1070913">Table 0.3</a> describes the various attributes you can use in the CONFIG section. </P></A>
|
||||
<A NAME="1070964">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="CONFIG section attributes
|
||||
"></A><A NAME="1070913"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.3 CONFIG section attributes
|
||||
@@ -883,7 +883,7 @@ The example below shows two machines that should always run identical loads. The
|
||||
<pre><A NAME="1087175"><FONT FACE="courier, courier new, monospace"><CLIENT HOSTS=client1,client2><br> arch SunOS5.6<br> maxThreads 500<br> maxClients 2000<br></CLIENT></FONT></A><P></pre><A NAME="1071076">
|
||||
Note that on NT, only one process is allowed. If the testmaster is running on NT, then only <FONT FACE="courier, courier new, monospace">localhost</FONT> is allowed as a CLIENT.</P></A>
|
||||
<A NAME="1087204">
|
||||
<a href="#1071356">Table 0.4</a> describes the various attributes you can use in the CLIENT section. </P></A>
|
||||
<a href="stone.htm#1071356">Table 0.4</a> describes the various attributes you can use in the CLIENT section. </P></A>
|
||||
<A NAME="1071395">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="CLIENT section attributes
|
||||
"></A><A NAME="1071356"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.4 CLIENT section attributes
|
||||
@@ -955,7 +955,7 @@ The PRETEST section defines commands to be run before the test starts. This is o
|
||||
<A NAME="1071434">
|
||||
The results of PRETEST will be linked to the final report.</P></A>
|
||||
<A NAME="1071439">
|
||||
<a href="#1071442">Table 0.5</a> describes the various attributes you can use in the PRETEST section. </P></A>
|
||||
<a href="stone.htm#1071442">Table 0.5</a> describes the various attributes you can use in the PRETEST section. </P></A>
|
||||
<A NAME="1071481">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="PRETEST section attributes
|
||||
"></A><A NAME="1071442"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.5 PRETEST section attributes
|
||||
@@ -983,7 +983,7 @@ The POSTTEST section defines commands to be run after the test ends. This is oft
|
||||
<A NAME="1071544">
|
||||
The results of POSTTEST will be linked to the final report.</P></A>
|
||||
<A NAME="1071548">
|
||||
<a href="#1071551">Table 0.6</a> describes the various attributes you can use in the POSTTEST section. </P></A>
|
||||
<a href="stone.htm#1071551">Table 0.6</a> describes the various attributes you can use in the POSTTEST section. </P></A>
|
||||
<A NAME="1071566">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="POSTTEST section attributes
|
||||
"></A><A NAME="1071551"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.6 POSTTEST section attributes
|
||||
@@ -1013,7 +1013,7 @@ The results of MONITOR will be linked to the final report.</P></A>
|
||||
<A NAME="1087152">
|
||||
On NT, any MONITOR sections will be ignored.</P></A>
|
||||
<A NAME="1071588">
|
||||
<a href="#1071591">Table 0.7</a> describes the various attributes you can use in the PRETEST section. </P></A>
|
||||
<a href="stone.htm#1071591">Table 0.7</a> describes the various attributes you can use in the PRETEST section. </P></A>
|
||||
<A NAME="1071606">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="PRETEST section attributes
|
||||
"></A><A NAME="1071591"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.7 PRETEST section attributes
|
||||
@@ -1048,7 +1048,7 @@ The GRAPH section defines each graph to be generated for the final report. If no
|
||||
<A NAME="1071767">
|
||||
In addition to the protocol timers, there is an internally generated "timer" called "connections". This contains the current server connection count, taking into account connects, logouts, and errors. To graph this timer, specify a variable of "connection".</P></A>
|
||||
<A NAME="1071649">
|
||||
<a href="#1071652">Table 0.8</a> describes the various attributes you can use in the GRAPH section. </P></A>
|
||||
<a href="stone.htm#1071652">Table 0.8</a> describes the various attributes you can use in the GRAPH section. </P></A>
|
||||
<A NAME="1071667">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="GRAPH section attributes
|
||||
"></A><A NAME="1071652"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.8 GRAPH section attributes
|
||||
@@ -1102,7 +1102,7 @@ This top level loop is use to run the protocol tests:</P></A>
|
||||
<pre><A NAME="1087687"><FONT FACE="courier, courier new, monospace">Select a section using a random number and the <I><FONT FACE="courier, courier new, monospace">weight</FONT></I> of each section.</FONT></A><P></pre><pre><A NAME="1087689"><FONT FACE="courier, courier new, monospace">Run the protocol initialization.</FONT></A><P></pre><pre><A NAME="1087690"><FONT FACE="courier, courier new, monospace">IDLE for <I><FONT FACE="courier, courier new, monospace">idleTime</FONT></I>.</FONT></A><P></pre><pre><A NAME="1087691"><FONT FACE="courier, courier new, monospace">Repeat this part <I><FONT FACE="courier, courier new, monospace">numLoops</FONT></I> times (or until test ends)<br>{</FONT></A><P></pre><pre><A NAME="1087692"><FONT FACE="courier, courier new, monospace"> Run the protocol loop body.</FONT></A><P></pre><pre><A NAME="1087700"><FONT FACE="courier, courier new, monospace"> IDLE for <I><FONT FACE="courier, courier new, monospace">loopDelay</FONT></I></FONT></A><P></pre><pre><A NAME="1087701"><FONT FACE="courier, courier new, monospace">}</FONT></A><P></pre><pre><A NAME="1087702"><FONT FACE="courier, courier new, monospace">Run the protocol conclusion.</FONT></A><P></pre><pre><A NAME="1087703"><FONT FACE="courier, courier new, monospace">IDLE for <I><FONT FACE="courier, courier new, monospace">blockTime</FONT></I></FONT></A><P></pre><A NAME="1087728">
|
||||
Note that an error will cause the section to be aborted and the connection closed. However, the final IDLE for <I><FONT FACE="courier, courier new, monospace">blockTime</FONT></I> will still be performed. If the test time is up, then all IDLE calls will return immediately and no more loops will be performed.</P></A>
|
||||
<A NAME="1079583">
|
||||
<a href="#1079587">Table 0.9</a> describes attributes that all protocol sections support.</P></A>
|
||||
<a href="stone.htm#1079587">Table 0.9</a> describes attributes that all protocol sections support.</P></A>
|
||||
<A NAME="1079638">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="General protocol section attributes
|
||||
"></A><A NAME="1079587"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.9 General protocol section attributes
|
||||
@@ -1145,7 +1145,7 @@ checks. Defaults to 0.
|
||||
<tr><td valign=top><A NAME="1079624"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1><FONT FACE="courier, courier new, monospace">numLoops </FONT><I><FONT FACE="courier, courier new, monospace">N
|
||||
</FONT></I></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1079626"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>Specifies the number of loops to perform before closing the
|
||||
connection. See <a href="#1061888">Detailed Protocol Test Steps</a> for what is
|
||||
connection. See <a href="stone.htm#1061888">Detailed Protocol Test Steps</a> for what is
|
||||
done in each loop. Defaults to 1.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
@@ -1153,7 +1153,7 @@ done in each loop. Defaults to 1.
|
||||
<tr><td valign=top><A NAME="1079632"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1><FONT FACE="courier, courier new, monospace">weight </FONT><I><FONT FACE="courier, courier new, monospace">N
|
||||
</FONT></I></FONT></A><BR></td>
|
||||
<td valign=top><A NAME="1079634"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE=-1>Specifies the relative frequency of Mailstone running that
|
||||
command. See <a href="#1087645">Weights in Configuration Files</a> for details.
|
||||
command. See <a href="stone.htm#1087645">Weights in Configuration Files</a> for details.
|
||||
Defaults to 100.
|
||||
</FONT></A><BR></td>
|
||||
</tr>
|
||||
@@ -1190,7 +1190,7 @@ IMAP4 Protocol Steps</B></FONT></A><P>
|
||||
<A NAME="1088121">
|
||||
The IMAP protocol stores mail on the mail server and allows message management without downloading the whole message. Clients are usually connected for long periods of time and periodically check for new messages.</P></A>
|
||||
<A NAME="1066064">
|
||||
<a href="#1066068">Table 0.10</a> describes the various attributes you can use in the IMAP section. </P></A>
|
||||
<a href="stone.htm#1066068">Table 0.10</a> describes the various attributes you can use in the IMAP section. </P></A>
|
||||
<A NAME="1066222">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="IMAP section attributes
|
||||
"></A><A NAME="1066068"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.10 IMAP section attributes
|
||||
@@ -1290,7 +1290,7 @@ POP3 protocol steps:</B></FONT></A><P>
|
||||
<A NAME="1062228">
|
||||
The POP protocol transfers messages to the client for viewing and storage. The client connects long enough to download (and usually delete) messages and then disconnects.</P></A>
|
||||
<A NAME="1066455">
|
||||
<a href="#1066459">Table 0.11</a> describes the various attributes you can use in the POP3 section. </P></A>
|
||||
<a href="stone.htm#1066459">Table 0.11</a> describes the various attributes you can use in the POP3 section. </P></A>
|
||||
<A NAME="1066514">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="POP3 section attributes
|
||||
"></A><A NAME="1066459"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.11 POP3 section attributes
|
||||
@@ -1380,7 +1380,7 @@ SMTP Protocol Steps</B></FONT></A><P>
|
||||
<A NAME="1087293">
|
||||
The SMTP protocol provides reliable message transfer. The mail server looks at the message addresses and either delivers the mail locally or sends it to another SMTP server. Each SMTP connection can deliver multiple messages, each of which can have multiple addresses.</P></A>
|
||||
<A NAME="1087297">
|
||||
<a href="#1087301">Table 0.12</a> describes the various attributes you can use in the SMTP section. </P></A>
|
||||
<a href="stone.htm#1087301">Table 0.12</a> describes the various attributes you can use in the SMTP section. </P></A>
|
||||
<A NAME="1087380">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="SMTP section attributes
|
||||
"></A><A NAME="1087301"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.12 SMTP section attributes
|
||||
@@ -1532,7 +1532,7 @@ Many parameters for WMAP can occur multiple times. Each occurrence is added to a
|
||||
<A NAME="1087682">
|
||||
The WMAP protocol requires special handling of connection termination. Since WMAP is based on HTTP, the connection may be dropped and re-established arbitrarily. This will show up as a connection error and then an additional connection. Repeat connection failures or any other kind of error will cause the block to abort.</P></A>
|
||||
<A NAME="1066610">
|
||||
<a href="#1066614">Table 0.13</a> describes the various attributes you can use in the WMAP section. </P></A>
|
||||
<a href="stone.htm#1066614">Table 0.13</a> describes the various attributes you can use in the WMAP section. </P></A>
|
||||
<A NAME="1066669">
|
||||
<TABLE BORDER=1 cellpadding=4 cellspacing=3><CAPTION></caption><p><A NAME="WMAP section attributes
|
||||
"></A><A NAME="1066614"><FONT FACE="PrimaSans BT, Verdana, Sans-Serif"><B>Table 0.13 WMAP section attributes
|
||||
@@ -1827,4 +1827,4 @@ See the <I>Directory Server Administrator's Guide</I>, and online Help for more
|
||||
|
||||
</BODY>
|
||||
|
||||
</HTML>
|
||||
</HTML>
|
||||
@@ -48,11 +48,11 @@ run_nsarch() {
|
||||
|
||||
OUROS=`bin/nsarch`
|
||||
# deal with new versions of OS falling back to versions we have
|
||||
if [ ! -d build/$OUROS ] ; then
|
||||
if [ ! -d bin/$OUROS ] ; then
|
||||
shortos=`echo $OUROS | sed -e 's/[0-9].*//'`
|
||||
near=`ls build | grep $shortos`
|
||||
near=`ls -d bin/*/bin | grep $shortos`
|
||||
if [ -n "$near" ] ; then
|
||||
near=`echo $near | cut -f2 -d' '`
|
||||
near=`echo $near | cut -f2 -d'/'`
|
||||
echo "No support for $OUROS, using $near"
|
||||
OUROS=$near
|
||||
else
|
||||
@@ -85,7 +85,7 @@ setup_perl() {
|
||||
# Get the default version of mailclient
|
||||
setup_mailclient() {
|
||||
[ -n "$OUROS" ] || run_nsarch $1
|
||||
(cd bin; ln -s ../build/$OUROS/mailclient ./ )
|
||||
(cd bin; ln -s $OUROS/bin/mailclient ./ )
|
||||
}
|
||||
|
||||
# setup_file source_dir directory filename
|
||||
|
||||
@@ -47,9 +47,7 @@ STONE = $(OBJDIR)/mailclient$(EXE_SUFFIX)
|
||||
|
||||
STONESRCS = bench.c client.c errexit.c main.c \
|
||||
parse.c sysdep.c timefunc.c \
|
||||
http-util.c http.c imap4.c pop3.c smtp.c wmap.c \
|
||||
idle.c generate.c socket.c multipop.c webmail.c \
|
||||
xalloc.c sb.c $(FEATURE_SRCS)
|
||||
http-util.c http.c imap4.c pop3.c smtp.c wmap.c
|
||||
|
||||
STONEOBJS = $(addprefix $(OBJDIR)/, $(STONESRCS:.c=.$(OBJ_SUFFIX)) )
|
||||
|
||||
@@ -61,25 +59,25 @@ $(OBJDIR):
|
||||
|
||||
$(STONE): $(STONEOBJS) Makefile
|
||||
@$(ECHO) "\n===== [`date`] making $(STONE)...\n"
|
||||
$(COMPILE) $(STONEOBJS) $(LIBS) $(OS_LINKFLAGS) -o $(STONE)
|
||||
$(COMPILE) $(STONEOBJS) $(LIBPATH) $(LIBS) $(OS_LINKFLAGS) -o $(STONE)
|
||||
|
||||
$(OBJDIR)/bench.$(OBJ_SUFFIX): bench.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/client.$(OBJ_SUFFIX): client.c bench.h sysdep.h idle.h Makefile
|
||||
$(OBJDIR)/client.$(OBJ_SUFFIX): client.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/errexit.$(OBJ_SUFFIX): errexit.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/http.$(OBJ_SUFFIX): http.c bench.h sysdep.h http-util.h Makefile
|
||||
|
||||
$(OBJDIR)/imap4.$(OBJ_SUFFIX): imap4.c bench.h pish.h sysdep.h idle.h Makefile
|
||||
$(OBJDIR)/imap4.$(OBJ_SUFFIX): imap4.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/main.$(OBJ_SUFFIX): main.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/parse.$(OBJ_SUFFIX): parse.c bench.h sysdep.h Makefile generate.h
|
||||
$(OBJDIR)/parse.$(OBJ_SUFFIX): parse.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/pop3.$(OBJ_SUFFIX): pop3.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/smtp.$(OBJ_SUFFIX): smtp.c bench.h pish.h sysdep.h Makefile generate.h
|
||||
$(OBJDIR)/smtp.$(OBJ_SUFFIX): smtp.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/stats.$(OBJ_SUFFIX): stats.c bench.h sysdep.h Makefile
|
||||
|
||||
@@ -91,24 +89,6 @@ $(OBJDIR)/wmap.$(OBJ_SUFFIX): wmap.c bench.h sysdep.h Makefile http-util.h
|
||||
|
||||
$(OBJDIR)/http-util.$(OBJ_SUFFIX): http-util.c bench.h sysdep.h Makefile http-util.h
|
||||
|
||||
$(OBJDIR)/idle.$(OBJ_SUFFIX): idle.c idle.h bench.h Makefile
|
||||
|
||||
$(OBJDIR)/generate.$(OBJ_SUFFIX): generate.c generate.h bench.h idle.h Makefile
|
||||
|
||||
$(OBJDIR)/socket.$(OBJ_SUFFIX): socket.c socket.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/multipop.$(OBJ_SUFFIX): multipop.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/webmail.$(OBJ_SUFFIX): webmail.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/event.$(OBJ_SUFFIX): event.c event.h Makefile
|
||||
|
||||
$(OBJDIR)/checksum.$(OBJ_SUFFIX): checksum.c checksum.h Makefile
|
||||
|
||||
$(OBJDIR)/sb.$(OBJ_SUFFIX): sb.c sb.h Makefile
|
||||
|
||||
$(OBJDIR)/md5.$(OBJ_SUFFIX): md5.c md5.h Makefile
|
||||
|
||||
# currently broken. See ../Makefile for packaging
|
||||
install: all
|
||||
$(CP) $(STONE) $(BINDIR)
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -38,7 +37,57 @@
|
||||
bench.c has all the OS independent utilities.
|
||||
*/
|
||||
#include "bench.h"
|
||||
#include "checksum.h"
|
||||
|
||||
/* allocate memory and exit if out of memory */
|
||||
void *
|
||||
mymalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
if (ptr == NULL)
|
||||
errexit(stderr, "Call to malloc(%d) failed\n", size);
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
void *
|
||||
mycalloc(size_t size)
|
||||
{
|
||||
void *retp;
|
||||
|
||||
if ((retp = mymalloc(size)) == NULL)
|
||||
return NULL;
|
||||
memset(retp, 0, size);
|
||||
return(retp);
|
||||
}
|
||||
|
||||
/* allocate memory and exit if out of memory */
|
||||
void *
|
||||
myrealloc(void *ptr, size_t size)
|
||||
{
|
||||
ptr = realloc(ptr, size);
|
||||
if (ptr == NULL)
|
||||
errexit(stderr, "Call to realloc(%d, %d) failed\n", ptr, size);
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
myfree(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
char *
|
||||
mystrdup(const char *cp)
|
||||
{
|
||||
char *retcp;
|
||||
|
||||
if ((retcp = (char *)mymalloc(strlen(cp)+1)) == NULL)
|
||||
return NULL;
|
||||
strcpy(retcp, cp);
|
||||
|
||||
return retcp;
|
||||
}
|
||||
|
||||
/*
|
||||
* waitReadWrite(int fd, int flags)
|
||||
@@ -56,20 +105,21 @@
|
||||
#define CHECK_ALL 0x3
|
||||
#define CHECK_FOREVER 0x4
|
||||
|
||||
#define waitReadable(fd, t) waitReadWrite((fd), (t), CHECK_READ)
|
||||
#define waitWriteable(fd, t) waitReadWrite((fd), (t), CHECK_WRITE)
|
||||
#define waitWriteableForever(fd) waitReadWrite((fd), -1, CHECK_WRITE | CHECK_FOREVER)
|
||||
#define waitReadable(fd) waitReadWrite((fd),CHECK_READ)
|
||||
#define waitWriteable(fd) waitReadWrite((fd),CHECK_WRITE)
|
||||
#define waitWriteableForever(fd) waitReadWrite((fd),CHECK_WRITE | CHECK_FOREVER)
|
||||
|
||||
/* Return 1 if bytes readable; 0 if error or time up */
|
||||
int
|
||||
waitReadWrite(SOCKET s, int timeout, int flags)
|
||||
waitReadWrite(int fd, int flags)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return 0;
|
||||
#else
|
||||
int fd = SOCK_FD(s);
|
||||
struct pollfd pfd;
|
||||
int timeleft;
|
||||
int ret;
|
||||
int timeouts = 0;
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLHUP;
|
||||
@@ -81,28 +131,41 @@ waitReadWrite(SOCKET s, int timeout, int flags)
|
||||
} else if ((flags & CHECK_ALL) == CHECK_RW) {
|
||||
pfd.events |= (POLLIN | POLLOUT);
|
||||
}
|
||||
|
||||
if (flags & CHECK_FOREVER) {
|
||||
timeout = 0; /* truly forever */
|
||||
} else {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(stderr, "waitReadWrite gf_timeexpired=%d\n",
|
||||
gf_timeexpired);
|
||||
return 0;
|
||||
for (;;) {
|
||||
if (flags & CHECK_FOREVER) { /* for writing status out */
|
||||
timeleft = 60;
|
||||
} else {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(stderr, "waitReadWrite gf_timeexpired=%d\n",
|
||||
gf_timeexpired);
|
||||
return 0;
|
||||
}
|
||||
timeleft = 5;
|
||||
}
|
||||
|
||||
/*fprintf(stderr, "poll(%d,%d)\n", fd, timeleft*1000);*/
|
||||
ret = poll(&pfd, 1, timeleft*1000);
|
||||
/*fprintf(stderr, "poll(%d,%d)=%d\n", fd, timeleft*1000, ret);*/
|
||||
|
||||
if (ret == 0) {
|
||||
if (!(flags & CHECK_FOREVER) && (++timeouts >= 12)) {
|
||||
return 0; /* time out after 60sec total */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
D_PRINTF(stderr, "waitReadWrite error ret=%d\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
try_again:
|
||||
ret = poll(&pfd, 1, timeout);
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
goto try_again;
|
||||
D_PRINTF(stderr, "waitReadWrite error ret=%d\n", ret);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* error */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -113,14 +176,14 @@ retryRead(ptcx_t ptcx, SOCKET sock, char *buf, int count)
|
||||
int bytesread = 0;
|
||||
|
||||
D_PRINTF(debugfile, "retryRead(%d, %d (gf_timeexpired=%d))\n",
|
||||
SOCK_FD(sock), count, gf_timeexpired);
|
||||
sock, count, gf_timeexpired);
|
||||
while (count) {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF (debugfile, "retryRead gf_timeexpired\n");
|
||||
strcpy (ptcx->errMsg, "retryRead:TIMEOUT");
|
||||
break;
|
||||
}
|
||||
if (0 == waitReadable (sock, ptcx->net_timeout)) {
|
||||
if (0 == waitReadable (sock)) {
|
||||
D_PRINTF (debugfile, "retryRead waitReadable time/error\n");
|
||||
strcpy (ptcx->errMsg, "waitReadable TIMEOUT<retryRead");
|
||||
break;
|
||||
@@ -132,27 +195,22 @@ retryRead(ptcx_t ptcx, SOCKET sock, char *buf, int count)
|
||||
if (errno == EAGAIN) {
|
||||
if (bytesread > 0)
|
||||
break; /* return what we got so far */
|
||||
if (waitReadable(sock, ptcx->net_timeout)) {
|
||||
if (waitReadable(sock)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (bytesread == 0) {
|
||||
bytesread = -1;
|
||||
}
|
||||
sprintf (ptcx->errMsg, "retryRead(sock=%d) IO error",
|
||||
SOCK_FD(sock));
|
||||
sprintf (ptcx->errMsg, "retryRead(sock=%d) IO error", sock);
|
||||
break;
|
||||
}
|
||||
if(ret == 0 && errno == EAGAIN)
|
||||
continue;
|
||||
|
||||
}
|
||||
bytesread += ret;
|
||||
buf += ret;
|
||||
count -= ret;
|
||||
break; /* return any good bytes */
|
||||
}
|
||||
D_PRINTF(debugfile, "retryRead(%d, %d)=%d\n", SOCK_FD(sock),
|
||||
count, bytesread);
|
||||
D_PRINTF(debugfile, "retryRead(%d, %d)=%d\n", sock, count, bytesread);
|
||||
return bytesread;
|
||||
}
|
||||
|
||||
@@ -162,7 +220,7 @@ retryWrite(ptcx_t ptcx, SOCKET sock, char *buf, int count)
|
||||
int ret;
|
||||
int byteswritten = 0;
|
||||
|
||||
D_PRINTF(debugfile, "retryWrite(%d, %d)...\n", SOCK_FD(sock), count);
|
||||
D_PRINTF(debugfile, "retryWrite(%d, %d)...\n", sock, count);
|
||||
while (count) {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF (debugfile, "retryWrite gf_timeexpired\n");
|
||||
@@ -174,7 +232,7 @@ retryWrite(ptcx_t ptcx, SOCKET sock, char *buf, int count)
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN) {
|
||||
if (waitWriteable(sock, ptcx->net_timeout)) {
|
||||
if (waitWriteable(sock)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -182,16 +240,14 @@ retryWrite(ptcx_t ptcx, SOCKET sock, char *buf, int count)
|
||||
byteswritten = -1;
|
||||
}
|
||||
sprintf (ptcx->errMsg,
|
||||
"retryWrite(sock=%d, n=%d) IO error",
|
||||
SOCK_FD(sock), count);
|
||||
"retryWrite(sock=%d, n=%d) IO error", sock, count);
|
||||
break;
|
||||
}
|
||||
byteswritten += ret;
|
||||
buf += ret;
|
||||
count -= ret;
|
||||
}
|
||||
D_PRINTF(debugfile, "retryWrite(%d, %d)=%d\n",
|
||||
SOCK_FD(sock), count, byteswritten);
|
||||
D_PRINTF(debugfile, "retryWrite(%d, ?)=%d\n", sock, byteswritten);
|
||||
return byteswritten;
|
||||
}
|
||||
|
||||
@@ -313,9 +369,9 @@ sendOutput(int fd, char *string)
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN) {
|
||||
/* if (waitWriteableForever(fd)) */
|
||||
/* continue; */
|
||||
/* else */
|
||||
if (waitWriteableForever(fd))
|
||||
continue;
|
||||
else
|
||||
returnerr(stderr,
|
||||
"sendOutput(%d) - Got EAGAIN and fd not ready\n",
|
||||
fd); /* has this ever happened? die??? */
|
||||
@@ -325,25 +381,35 @@ sendOutput(int fd, char *string)
|
||||
|
||||
sentbytes += sent;
|
||||
|
||||
#if 0
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(stderr,"sendOutput() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return sentbytes;
|
||||
}
|
||||
|
||||
/* read from socket until we find <CRLF>.<CRLF>, throwing it away as
|
||||
we go. */
|
||||
/* read from socket until we find <CRLF>.<CRLF> */
|
||||
int
|
||||
retrMsg(ptcx_t ptcx, SOCKET sock)
|
||||
retrMsg(ptcx_t ptcx, char *buffer, int maxBytes, SOCKET sock)
|
||||
{
|
||||
int totalbytesread = 0;
|
||||
int bytesread;
|
||||
int sz;
|
||||
char garbage[10000], *sp;
|
||||
|
||||
sp = garbage;
|
||||
sz = sizeof (garbage)-1;
|
||||
|
||||
while (1) {
|
||||
if (buffer) {
|
||||
sp = buffer;
|
||||
sz = maxBytes-1;
|
||||
} else {
|
||||
sp = garbage;
|
||||
sz = sizeof (garbage)-1;
|
||||
}
|
||||
|
||||
while (!buffer || (totalbytesread < maxBytes)) {
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"Time expired while reading messages - in retrMsg\n");
|
||||
break;
|
||||
@@ -373,7 +439,7 @@ retrMsg(ptcx_t ptcx, SOCKET sock)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (totalbytesread > 5) { /* reset our scratch buffer */
|
||||
if (!buffer && (totalbytesread > 5)) { /* reset our scratch buffer */
|
||||
int i;
|
||||
char *from, *to;
|
||||
/* shuffle last 5 bytes to start */
|
||||
@@ -385,6 +451,7 @@ retrMsg(ptcx_t ptcx, SOCKET sock)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return totalbytesread;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
* David Shak
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -39,10 +37,6 @@
|
||||
#ifndef __BENCH_H__
|
||||
#define __BENCH_H__
|
||||
|
||||
#ifdef USE_PTHREADS
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
@@ -61,6 +55,10 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#ifdef USE_PTHREADS
|
||||
#include <sys/signal.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -71,53 +69,14 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/poll.h>
|
||||
|
||||
/*
|
||||
* thom@sendmail.com, 2004/06/07
|
||||
* This FREEBSD define prevents building mstone on post-FreeBSD 4.8
|
||||
* so removing it
|
||||
* #ifdef __FREEBSD__
|
||||
* #define poll _thread_sys_poll
|
||||
* #endif
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#ifndef timersub
|
||||
/* aix doesn't seem to define this */
|
||||
# define timersub(a, b, result) \
|
||||
do { \
|
||||
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
||||
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
|
||||
if ((result)->tv_usec < 0) { \
|
||||
--(result)->tv_sec; \
|
||||
(result)->tv_usec += 1000000; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /* timersub */
|
||||
#ifndef timeradd
|
||||
# define timeradd(a, b, result) \
|
||||
do { \
|
||||
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
|
||||
(result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
|
||||
if ((result)->tv_usec >= 1000000) \
|
||||
{ \
|
||||
++(result)->tv_sec; \
|
||||
(result)->tv_usec -= 1000000; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /* timeradd */
|
||||
#ifndef timercmp
|
||||
# define timercmp(a, b, CMP) \
|
||||
(((a)->tv_sec == (b)->tv_sec) ? \
|
||||
((a)->tv_usec CMP (b)->tv_usec) : \
|
||||
((a)->tv_sec CMP (b)->tv_sec))
|
||||
#endif /* timercmp */
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
@@ -132,10 +91,6 @@
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "idle.h"
|
||||
#include "constants.h"
|
||||
|
||||
#define USECINSEC 1000000
|
||||
#define MSECINSEC 1000
|
||||
#define MAX_ACCEPT_SECS 180 /* maximum time master will wait for listen() */
|
||||
@@ -156,6 +111,8 @@
|
||||
|
||||
#define MAX_USERNAME_LEN 32
|
||||
#define MAX_MAILADDR_LEN 64
|
||||
#define MAX_COMMAND_LEN (2*1024)
|
||||
#define MAX_RESPONSE_LEN (2*1024)
|
||||
#define MAX_ERRORMSG_LEN 256
|
||||
#define DATESTAMP_LEN 40
|
||||
|
||||
@@ -178,9 +135,6 @@
|
||||
#define D_PRINTF if (gn_debug > 0) d_printf
|
||||
#define T_PRINTF if (gn_record_telemetry) t_printf
|
||||
|
||||
/* make sure we don't pass NULL's to printf() and friends */
|
||||
#define PSTR(X) ((X)?(X):"(null)")
|
||||
|
||||
/*
|
||||
Simple keyword indexed string storage
|
||||
This kind of thing has been invented many times. Once more with gusto!
|
||||
@@ -287,24 +241,17 @@ typedef struct mail_command {
|
||||
/* These are protocol independent (client.c) */
|
||||
int blockID; /* ID number for each block */
|
||||
int numLoops; /* typically messages per connection */
|
||||
int idleTime; /* time to idle before loops */
|
||||
int loopDelay; /* time to idle after each loop */
|
||||
int blockTime; /* time to idle after block */
|
||||
int throttle; /* to simulate ops/sec (BROKEN) */
|
||||
|
||||
/* Sean O'Rourke: added startDelay to simulate arrival rates */
|
||||
dinst_t *startDelay;
|
||||
dinst_t *idleTime;
|
||||
dinst_t *loopDelay;
|
||||
dinst_t *blockTime;
|
||||
|
||||
/* XXX: not threadsafe! */
|
||||
double throttle; /* throttling factor */
|
||||
int loopThrottle; /* loopDelay over/underrun for throttling */
|
||||
double throttleFactor; /* multiple by which to change throttle rate */
|
||||
|
||||
void *data; /* protocol specific data */
|
||||
} mail_command_t;
|
||||
|
||||
typedef struct child_context { /* forked sub processes */
|
||||
int pid;
|
||||
_SOCKET socket;
|
||||
SOCKET socket;
|
||||
} ccx_t, *pccx_t;
|
||||
|
||||
typedef struct thread_context {
|
||||
@@ -317,6 +264,7 @@ typedef struct thread_context {
|
||||
/* local thread context, also read by parent */
|
||||
int blockCount; /* how many command blocks */
|
||||
int connectCount; /* how many connections */
|
||||
stats_t timestat; /* throttle info */
|
||||
cmd_stats_t *cmd_stats; /* stats for each command */
|
||||
|
||||
/* temporary storage (event_start, event_stop) */
|
||||
@@ -328,19 +276,8 @@ typedef struct thread_context {
|
||||
FILE *dfile; /* debug file */
|
||||
int logfile; /* telemetry log file */
|
||||
|
||||
#ifdef USE_EVENTS
|
||||
int ev_loop; /* loops left for current event */
|
||||
struct timeval ev_next; /* time to schedule next init */
|
||||
void * ev_state; /* client state */
|
||||
mail_command_t * ev_comm;
|
||||
cmd_stats_t * ev_stats;
|
||||
|
||||
#endif /* USE_EVENTS */
|
||||
|
||||
SOCKET sock; /* network connection */
|
||||
char errMsg[MAX_ERRORMSG_LEN]; /* low level error string */
|
||||
|
||||
int net_timeout; /* timeout for network ops (msec) */
|
||||
} tcx_t;
|
||||
|
||||
/* About errMsg:
|
||||
@@ -363,6 +300,13 @@ typedef struct thread_context {
|
||||
*/
|
||||
#define debugfile (ptcx->dfile)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
/* routines in bench.c */
|
||||
extern void event_start(ptcx_t ptcx, event_timer_t *pevent);
|
||||
extern void event_stop(ptcx_t ptcx, event_timer_t *pevent);
|
||||
@@ -408,12 +352,16 @@ extern const char *gs_eventToTextFormat;
|
||||
|
||||
|
||||
/* more routines in bench.c */
|
||||
extern void *mymalloc(size_t size);
|
||||
extern void *mycalloc(size_t size);
|
||||
extern void *myrealloc(void *ptr, size_t size);
|
||||
extern void myfree(void *ptr);
|
||||
extern char *mystrdup(const char *cp);
|
||||
|
||||
extern int timeval_clear(struct timeval *tv);
|
||||
extern int timeval_stamp(struct timeval *tv);
|
||||
|
||||
/* extern int waitReadWrite(int fd, int flags); */
|
||||
extern int waitReadWrite(SOCKET s, int timeout, int flags);
|
||||
extern int waitReadWrite(int fd, int flags);
|
||||
extern int retryRead(ptcx_t ptcx, SOCKET sock, char *buf, int count);
|
||||
extern int retryWrite(ptcx_t ptcx, SOCKET sock, char *buf, int count);
|
||||
|
||||
@@ -425,7 +373,7 @@ extern int readResponse(ptcx_t ptcx, SOCKET sock, char *buffer, int buflen);
|
||||
extern int sendCommand(ptcx_t ptcx, SOCKET sock, char *command);
|
||||
extern int doCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen);
|
||||
extern int sendOutput(int fd, char *command);
|
||||
extern int retrMsg(ptcx_t ptcx, SOCKET sock);
|
||||
extern int retrMsg(ptcx_t ptcx, char *buffer, int maxBytes, SOCKET sock);
|
||||
extern void trimEndWhite (char *buff);
|
||||
unsigned long rangeNext (range_t *, unsigned long );
|
||||
void rangeSetFirstLast (range_t *, unsigned long , unsigned long , int );
|
||||
@@ -464,19 +412,6 @@ extern void *doPop3Start(ptcx_t ptcx, pmail_command_t, cmd_stats_t *);
|
||||
extern int doPop3Loop(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
|
||||
extern void doPop3End(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
|
||||
|
||||
/* in multipop.c */
|
||||
extern int MPopParseStart (pmail_command_t , char *, param_list_t *);
|
||||
extern int MPopParseEnd (pmail_command_t , string_list_t *, param_list_t *);
|
||||
extern void *MPopCheckStart(ptcx_t ptcx, pmail_command_t, cmd_stats_t *);
|
||||
extern int MPopCheck(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
|
||||
extern void MPopCheckEnd(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
|
||||
|
||||
/* in webmail.c */
|
||||
extern int WebmailParseStart (pmail_command_t , char *, param_list_t *);
|
||||
extern int WebmailParseEnd (pmail_command_t , string_list_t *, param_list_t *);
|
||||
extern void *doWebmailStart(ptcx_t ptcx, pmail_command_t, cmd_stats_t *);
|
||||
extern int doWebmailLoop(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
|
||||
extern void doWebmailEnd(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
|
||||
|
||||
/* routines in imap4.c */
|
||||
extern int Imap4ParseStart (pmail_command_t , char *, param_list_t *);
|
||||
@@ -512,8 +447,6 @@ extern char *string_tolower(char *string);
|
||||
extern char *string_unquote(char *string);
|
||||
extern int cmdParseNameValue (pmail_command_t cmd, char *name, char *tok);
|
||||
extern int time_atoi(const char *pstr);
|
||||
extern int millitime_atoi(const char *pstr);
|
||||
extern double size_atof(const char *);
|
||||
extern int load_commands(char *commands);
|
||||
extern param_list_t *paramListInit (void);
|
||||
/* paramListAdd returns: 1 update existing value, 0 new, -1 out of memory */
|
||||
@@ -545,8 +478,7 @@ extern int clientLoop(ptcx_t ptcx);
|
||||
extern THREAD_RET clientThread(void *);
|
||||
extern void clientSummary(ptcx_t ptcxs, int ntcxs, int ii, int outfd);
|
||||
extern THREAD_RET summaryThread(void *);
|
||||
/* extern int clientProc(int pnum, SOCKET outfd, unsigned int timeleft, unsigned int thread_stagger_usec); */
|
||||
extern int clientProc(int pnum, int outfd, unsigned int timeleft, unsigned int thread_stagger_usec);
|
||||
extern int clientProc(int pnum, SOCKET outfd, unsigned int timeleft, unsigned int thread_stagger_usec);
|
||||
|
||||
extern void MS_idle(ptcx_t ptcx, int idleSecs);
|
||||
extern int resolve_addrs(char *host, char *protocol, struct hostent *host_phe,
|
||||
@@ -561,7 +493,7 @@ unsigned long get_next_address(ptcx_t ptcx, mail_command_t *comm, cmd_stats_t *p
|
||||
#endif
|
||||
|
||||
#undef VERSION
|
||||
#define VERSION "4.9"
|
||||
#define VERSION "4.2"
|
||||
#ifdef _DEBUG
|
||||
#define MAILCLIENT_VERSION "mailclient (" VERSION " DEBUG built " __DATE__ " " __TIME__ ")"
|
||||
#else
|
||||
@@ -576,15 +508,7 @@ extern int getopt(int, char *const *, const char *);
|
||||
#ifndef __LINUX__
|
||||
extern long random(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* miscellaneous */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x,y) (((x) >= (y)) ? (x) : (y))
|
||||
extern void srandom(unsigned);
|
||||
#endif
|
||||
|
||||
#endif /* !__BENCH_H__ */
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#include "checksum.h"
|
||||
#include "xalloc.h"
|
||||
#include "sb.h"
|
||||
/* openldap md5 functions */
|
||||
#include "md5.h"
|
||||
|
||||
struct checksum_t
|
||||
{
|
||||
cs_type_t type;
|
||||
union {
|
||||
struct lutil_MD5Context md5;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct checksum_t *
|
||||
cs_begin(cs_type_t cstype)
|
||||
{
|
||||
struct checksum_t * ret = XALLOC(struct checksum_t);
|
||||
|
||||
ret->type = cstype;
|
||||
switch (cstype)
|
||||
{
|
||||
case CS_MD5:
|
||||
lutil_MD5Init(&ret->u.md5);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
cs_data(struct checksum_t * state, char * buf, int len)
|
||||
{
|
||||
assert(state != NULL);
|
||||
assert(buf != NULL);
|
||||
|
||||
switch (state->type)
|
||||
{
|
||||
case CS_MD5:
|
||||
lutil_MD5Update(&state->u.md5, (unsigned char *)buf, len);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
};
|
||||
}
|
||||
|
||||
char *
|
||||
cs_end(struct checksum_t * state)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
assert(state != NULL);
|
||||
|
||||
switch (state->type)
|
||||
{
|
||||
case CS_MD5:
|
||||
{
|
||||
unsigned char digest[16];
|
||||
lutil_MD5Final(digest, &state->u.md5);
|
||||
ret = xalloc(32 + strlen(CS_MARKER "MD5=") + 1);
|
||||
sprintf(ret, CS_MARKER "MD5=%08lx%08lx%08lx%08lx",
|
||||
*(unsigned long*)digest,
|
||||
*(unsigned long*)(digest + 4),
|
||||
*(unsigned long*)(digest + 8),
|
||||
*(unsigned long*)(digest + 12));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
cs_retrieve(ptcx_t ptcx, SOCKET sock, char *msg_start, char *msg_term)
|
||||
{
|
||||
socket_buffer * sb;
|
||||
struct checksum_t * cs;
|
||||
char *cs_value;
|
||||
char *cs_seen;
|
||||
|
||||
int nread;
|
||||
int msg_term_len;
|
||||
int ret = -1;
|
||||
|
||||
cs = NULL;
|
||||
cs_value = NULL;
|
||||
sb = sb_new(sock, 4096);
|
||||
msg_term_len = strlen(msg_term);
|
||||
|
||||
/* skip to start of message */
|
||||
if (sb_discard(ptcx, sb, msg_start) < 0)
|
||||
goto CLEANUP;
|
||||
|
||||
/* checksum over body */
|
||||
cs = cs_begin(CS_MD5);
|
||||
for (;;)
|
||||
{
|
||||
nread = sb_get(ptcx, sb, msg_term);
|
||||
if (nread < 0)
|
||||
{
|
||||
D_PRINTF (debugfile, "EOF looking for checksum\n");
|
||||
ret = 2; /* XXX: might be error */
|
||||
goto CLEANUP;
|
||||
}
|
||||
else if (strncmp(sb->buf + nread,
|
||||
msg_term, msg_term_len) == 0)
|
||||
break;
|
||||
|
||||
if (nread > CS_MAXLEN)
|
||||
{
|
||||
/* do more checksumming */
|
||||
cs_data(cs, sb->buf, nread - CS_MAXLEN);
|
||||
sb_discardn(ptcx, sb, nread - CS_MAXLEN);
|
||||
}
|
||||
}
|
||||
/* sb->buf + nread is the start of msg_term */
|
||||
|
||||
sb->buf[nread] = '\0';
|
||||
if (nread < CS_MAXLEN)
|
||||
cs_seen = sb->buf;
|
||||
else
|
||||
cs_seen = sb->buf + nread - CS_MAXLEN;
|
||||
|
||||
cs_seen = strstr(cs_seen, CS_MARKER);
|
||||
|
||||
if (cs_seen == NULL)
|
||||
{
|
||||
ret = 2;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
/* remember the last bit of message left in buffer */
|
||||
cs_data(cs, sb->buf, cs_seen - sb->buf);
|
||||
cs_value = cs_end(cs);
|
||||
|
||||
if (strncmp(cs_seen, cs_value, strlen(cs_value)) == 0)
|
||||
ret = 1;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
CLEANUP:
|
||||
switch (ret)
|
||||
{
|
||||
case -1:
|
||||
D_PRINTF(stderr, "retrMsg: ERROR checksum\n");
|
||||
break;
|
||||
case 0:
|
||||
D_PRINTF(stderr, "retrMsg: BAD checksum\n");
|
||||
break;
|
||||
case 1:
|
||||
D_PRINTF(stderr, "retrMsg: OK checksum\n");
|
||||
break;
|
||||
case 2:
|
||||
D_PRINTF(stderr, "retrMsg: NO checksum\n");
|
||||
break;
|
||||
};
|
||||
|
||||
if (cs)
|
||||
xfree(cs);
|
||||
if (cs_value)
|
||||
xfree(cs_value);
|
||||
if (sb)
|
||||
sb_delete(sb);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _checksum_h
|
||||
#define _checksum_h
|
||||
|
||||
#include "bench.h"
|
||||
|
||||
typedef enum {
|
||||
CS_MD5, /* MD5 hash */
|
||||
CS_NTYPES
|
||||
} cs_type_t;
|
||||
|
||||
/*
|
||||
** CS_MARKER marks the start of a checksum. It should be something
|
||||
** that will not otherwise appear in the text.
|
||||
*/
|
||||
|
||||
#define CS_MARKER CRLF "=CS="
|
||||
|
||||
#define CS_MAXLEN 64
|
||||
|
||||
/*
|
||||
** CS_BEGIN(t) -- start cstype-type checksum
|
||||
**
|
||||
** This routine will never return NULL.
|
||||
*/
|
||||
|
||||
struct checksum_t *
|
||||
cs_begin(cs_type_t cstype);
|
||||
|
||||
/*
|
||||
** CS_DATA(state, buf, len) -- sum another buffer
|
||||
*/
|
||||
|
||||
void
|
||||
cs_data(struct checksum_t * state, char * buf, int len);
|
||||
|
||||
/*
|
||||
** CS_END(state) -- return checksum value.
|
||||
**
|
||||
** The value returned is a printable string starting with
|
||||
** CS_MARKER, which should be freed using xfree(). cs_end() may
|
||||
** be called any number of times, but cs_data may not be called
|
||||
** after the first call to cs_end().
|
||||
*/
|
||||
|
||||
char *
|
||||
cs_end(struct checksum_t * state);
|
||||
|
||||
/*
|
||||
** CS_RETRIEVE(ptcx, sock, msg_start, msg_term) -- verify a message
|
||||
**
|
||||
** A convenience routine to allow retrieval protocols to
|
||||
** calculate checksums over retrieved messages, cs_retrieve reads
|
||||
** data from sock up to and including the first instance of
|
||||
** msg_term. The checksum is calculated over all data beteween
|
||||
** the first instance of msg_start and the first subsequent
|
||||
** CS_MARKER. If CS_MARKER is found, the computed checksum is
|
||||
** compared with the data at CS_MARKER.
|
||||
**
|
||||
** Returns:
|
||||
** -1 -- read error.
|
||||
** 0 -- invalid checksum found.
|
||||
** 1 -- valid checksum found.
|
||||
** 2 -- no checksum.
|
||||
*/
|
||||
|
||||
int
|
||||
cs_retrieve(ptcx_t ptcx, SOCKET sock, char *msg_start, char *msg_term);
|
||||
|
||||
#endif /* _checksum_h */
|
||||
@@ -20,7 +20,6 @@
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -42,7 +41,6 @@
|
||||
*/
|
||||
|
||||
#include "bench.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static int StartedThreads = 0; /* counter semaphore for children */
|
||||
static int FinishedThreads = 0; /* counter semaphore for children */
|
||||
@@ -61,14 +59,13 @@ static int FinishedThreads = 0; /* counter semaphore for children */
|
||||
We dont check for signals because the only signal expected is test end
|
||||
*/
|
||||
void
|
||||
MS_idle(ptcx_t ptcx, int idleMillis)
|
||||
MS_idle(ptcx_t ptcx, int idleSecs)
|
||||
{
|
||||
int secsLeft = 0;
|
||||
|
||||
secsLeft = gt_shutdowntime - time(0L);
|
||||
|
||||
D_PRINTF(debugfile, "secsLeft=%d, idleSecs=%d\n",
|
||||
secsLeft, idleMillis/1000);
|
||||
D_PRINTF(debugfile, "secsLeft=%d, idleSecs=%d\n", secsLeft, idleSecs);
|
||||
|
||||
if (secsLeft <= 0) { /* time is up, start exiting */
|
||||
if (gf_timeexpired < EXIT_SOON)
|
||||
@@ -76,32 +73,40 @@ MS_idle(ptcx_t ptcx, int idleMillis)
|
||||
return;
|
||||
}
|
||||
|
||||
if (idleMillis/1000 > secsLeft)
|
||||
idleMillis = secsLeft*1000;
|
||||
|
||||
if (idleMillis <= 0)
|
||||
if (idleSecs > secsLeft) idleSecs = secsLeft;
|
||||
if (idleSecs <= 0) return;
|
||||
|
||||
MS_sleep(idleSecs);
|
||||
}
|
||||
|
||||
/* used by POP, SMTP, IMAP4 methods */
|
||||
void
|
||||
throttle(ptcx_t ptcx, mail_command_t *comm, cmd_stats_t *timer )
|
||||
{
|
||||
|
||||
int chokeSecs = 0;
|
||||
struct timeval exittime;
|
||||
|
||||
/* check if we need to throttle this puppy */
|
||||
if (comm->throttle <= 0)
|
||||
return;
|
||||
|
||||
MS_usleep(idleMillis*1000);
|
||||
}
|
||||
/* we probably have not reached NETCLOSE yet, so we do not
|
||||
know what timer->exittime is */
|
||||
timeval_stamp(&exittime);
|
||||
|
||||
/*
|
||||
** DELAY -- calculate delay time
|
||||
**
|
||||
** Delay for the rest of the time the block was supposed to take,
|
||||
** _or_ for the full delay time if we have run over.
|
||||
*/
|
||||
/* time to sleep = throttle - (exittime - entertime) */
|
||||
chokeSecs = comm->throttle - ( exittime.tv_sec - ptcx->starttime.tv_sec );
|
||||
|
||||
static int
|
||||
delay(delay, start_time)
|
||||
int delay;
|
||||
int start_time;
|
||||
{
|
||||
int cmd_time = (time(0) - start_time)*1000;
|
||||
if (delay >= cmd_time)
|
||||
delay -= cmd_time;
|
||||
return delay;
|
||||
}
|
||||
|
||||
/* if chokeSecs is negative, don't bother sleeping */
|
||||
if (chokeSecs > 0) {
|
||||
d_printf(debugfile, "throttle=%d, chokeSecs=%d\n",
|
||||
comm->throttle, chokeSecs);
|
||||
MS_idle(ptcx, chokeSecs);
|
||||
}
|
||||
|
||||
} /* end throttle */
|
||||
|
||||
/*
|
||||
* Perform the given command block
|
||||
@@ -119,13 +124,10 @@ do_command(ptcx_t ptcx, /* thread state */
|
||||
cmd_stats_t *cmd_stats = &(ptcx->cmd_stats[commNum]);
|
||||
int cnt, cntEnd; /* loop counters */
|
||||
void *state = NULL;
|
||||
int loop_delay, block_time; /* Sean O'Rourke: added */
|
||||
int block_start;
|
||||
|
||||
cntEnd = comm->numLoops+1; /* transfer count +1 */
|
||||
block_start = (int)time(0);
|
||||
D_PRINTF(debugfile, "do_command start t=%d commNum=%d cntEnd=%d\n",
|
||||
block_start, commNum, cntEnd);
|
||||
D_PRINTF(debugfile, "do_command start t=%lu commNum=%d cntEnd=%d\n",
|
||||
time(0L), commNum, cntEnd);
|
||||
|
||||
/* Start and End are special loop cases to make summations easier */
|
||||
for (cnt = 0; cnt <= cntEnd; cnt++) {
|
||||
@@ -141,78 +143,49 @@ do_command(ptcx_t ptcx, /* thread state */
|
||||
time(0L), cnt, cntEnd);
|
||||
|
||||
if (0 == cnt) { /* first time */
|
||||
int idle_time;
|
||||
if ((idle_time = sample(comm->startDelay)) > 0) {
|
||||
int real_start = gt_startedtime + idle_time / 1000;
|
||||
if (real_start > block_start) {
|
||||
MS_idle(ptcx, (real_start - block_start)*1000);
|
||||
block_start = real_start;
|
||||
}
|
||||
}
|
||||
cmd_stats->totalcommands++; /* track command blocks trys */
|
||||
state = (*(comm->proto->cmdStart)) (ptcx, comm, cmd_stats);
|
||||
if (NULL == state) {
|
||||
D_PRINTF(debugfile, "do_command Start returned NULL\n");
|
||||
break;
|
||||
}
|
||||
idle_time = sample(comm->idleTime);
|
||||
|
||||
if (idle_time && (gf_timeexpired < EXIT_SOON)) {
|
||||
idle_time -= (time(0) - block_start)*1000;
|
||||
if(idle_time > 0) {
|
||||
D_PRINTF(debugfile,"do_command delay %d after Setup\n",
|
||||
idle_time);
|
||||
event_start(ptcx, &cmd_stats->idle);
|
||||
MS_idle(ptcx, idle_time);
|
||||
event_stop(ptcx, &cmd_stats->idle);
|
||||
} else {
|
||||
D_PRINTF(debugfile,
|
||||
"Warning: behind %d msec for start\n",
|
||||
-idle_time);
|
||||
}
|
||||
}
|
||||
} else if ((cntEnd == cnt) && comm->proto->cmdEnd) { /* last */
|
||||
if (comm->idleTime && (gf_timeexpired < EXIT_SOON)) {
|
||||
D_PRINTF(debugfile,"do_command delay %d after Setup\n",
|
||||
comm->idleTime);
|
||||
event_start(ptcx, &cmd_stats->idle);
|
||||
MS_idle(ptcx, comm->idleTime);
|
||||
event_stop(ptcx, &cmd_stats->idle);
|
||||
}
|
||||
}
|
||||
else if ((cntEnd == cnt) && comm->proto->cmdEnd) { /* last */
|
||||
(*(comm->proto->cmdEnd)) (ptcx, comm, cmd_stats, state);
|
||||
break; /* done with loop */
|
||||
}
|
||||
else if (comm->proto->cmdLoop) { /* do transfers */
|
||||
int rc;
|
||||
int loop_start = time(0);
|
||||
rc = (*(comm->proto->cmdLoop)) (ptcx, comm, cmd_stats, state);
|
||||
if (rc < 0) {
|
||||
D_PRINTF(debugfile, "do_command Loop returned error/done\n");
|
||||
cnt = cntEnd -1; /* end loop */
|
||||
}
|
||||
/* do loopDelay even if error/done */
|
||||
|
||||
loop_delay = sample(comm->loopDelay);
|
||||
|
||||
if (loop_delay > 0 && (gf_timeexpired < EXIT_SOON)) {
|
||||
loop_delay = delay(loop_delay, loop_start);
|
||||
if(loop_delay > 0) {
|
||||
D_PRINTF(debugfile,"do_command delay %d in loop\n",
|
||||
loop_delay);
|
||||
event_start(ptcx, &cmd_stats->idle);
|
||||
MS_idle(ptcx, loop_delay);
|
||||
event_stop(ptcx, &cmd_stats->idle);
|
||||
}
|
||||
if (comm->loopDelay && (gf_timeexpired < EXIT_SOON)) {
|
||||
D_PRINTF(debugfile,"do_command delay %d in loop\n",
|
||||
comm->loopDelay);
|
||||
event_start(ptcx, &cmd_stats->idle);
|
||||
MS_idle(ptcx, comm->loopDelay);
|
||||
event_stop(ptcx, &cmd_stats->idle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
block_time = sample(comm->blockTime);
|
||||
|
||||
/* XXX: semantic change: blockTime now includes command time. */
|
||||
/* do blockTime even if we hit an error connecting */
|
||||
if ((block_time > 0) && (gf_timeexpired < EXIT_SOON)) {
|
||||
block_time = delay(block_time, block_start);
|
||||
if(block_time > 0) {
|
||||
D_PRINTF(debugfile,"do_command delay %d after Block\n",
|
||||
block_time);
|
||||
event_start(ptcx, &cmd_stats->idle);
|
||||
MS_idle(ptcx, block_time);
|
||||
event_stop(ptcx, &cmd_stats->idle);
|
||||
}
|
||||
if (comm->blockTime && (gf_timeexpired < EXIT_SOON)) {
|
||||
D_PRINTF(debugfile,"do_command delay %d after Block\n",
|
||||
comm->blockTime);
|
||||
event_start(ptcx, &cmd_stats->idle);
|
||||
MS_idle(ptcx, comm->blockTime);
|
||||
event_stop(ptcx, &cmd_stats->idle);
|
||||
}
|
||||
D_PRINTF(debugfile, "do_command end t=%lu commNum=%d cntEdn=%d\n",
|
||||
time(0L), commNum, cntEnd);
|
||||
@@ -241,6 +214,8 @@ clientInit(ptcx_t ptcx)
|
||||
}
|
||||
ptcx->dfile = fopen(debug_file_name, "w+");
|
||||
if (ptcx->dfile == NULL) {
|
||||
/*returnerr(stderr, "Can't open debug file\n");
|
||||
return -1;*/
|
||||
gn_debug = 0;
|
||||
d_printf (stderr, "Can't open debug file. Debug mode disabled\n");
|
||||
}
|
||||
@@ -263,6 +238,10 @@ clientInit(ptcx_t ptcx)
|
||||
SRANDOM(ptcx->random_seed);
|
||||
D_PRINTF(debugfile, "Random seed: 0x%08x\n", ptcx->random_seed );
|
||||
|
||||
stats_init(&ptcx->timestat);
|
||||
|
||||
ptcx->timestat.total_num_of_commands = gn_number_of_commands;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -306,6 +285,7 @@ clientLoop(ptcx_t ptcx)
|
||||
ran_number, gn_total_weight);
|
||||
comm_index--;
|
||||
}
|
||||
/*D_PRINTF(debugfile, "Final page index %d\n", comm_index );*/
|
||||
}
|
||||
|
||||
/* run the command */
|
||||
@@ -323,6 +303,24 @@ clientLoop(ptcx_t ptcx)
|
||||
break;
|
||||
}
|
||||
|
||||
/* throttle code mikeb@netscape.com
|
||||
* keeps client from going faster than client_throttle
|
||||
* operations per minute
|
||||
*/
|
||||
if (gn_client_throttle &&
|
||||
(ptcx->timestat.endtime.tv_sec > ptcx->timestat.starttime.tv_sec)) {
|
||||
timeval_stamp(&(ptcx->timestat.endtime));
|
||||
while ( 60 * ptcx->connectCount /
|
||||
(ptcx->timestat.endtime.tv_sec - ptcx->timestat.starttime.tv_sec)
|
||||
> gn_client_throttle ) {
|
||||
D_PRINTF(debugfile, "%.2f > %d, throttling\n",
|
||||
( 60 * ptcx->connectCount /
|
||||
(ptcx->timestat.endtime.tv_sec - ptcx->timestat.starttime.tv_sec) ),
|
||||
gn_client_throttle);
|
||||
/* sleep a little */
|
||||
MS_usleep( 100 );
|
||||
} /* end while too fast */
|
||||
}
|
||||
} /* END while blockCount */
|
||||
|
||||
return 0;
|
||||
@@ -341,6 +339,7 @@ clientThread(void *targ)
|
||||
char timeStamp[DATESTAMP_LEN];
|
||||
int ret = 0;
|
||||
tcx_t *ptcx = (ptcx_t)targ;
|
||||
/*char buf[256];*/
|
||||
|
||||
if (clientInit(ptcx)) { /* should never fail */
|
||||
#ifdef USE_PTHREADS
|
||||
@@ -352,6 +351,10 @@ clientThread(void *targ)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*sprintf(buf, "NOTICE: client process=%d thread=%d started\n",
|
||||
ptcx->processnum, ptcx->threadnum);
|
||||
sendOutput(ptcx->ofd, buf);*/
|
||||
|
||||
if (gn_debug) {
|
||||
/* write current time to debug file */
|
||||
time(¤tTime);
|
||||
@@ -366,13 +369,15 @@ clientThread(void *targ)
|
||||
/* Tell parent we're ready */
|
||||
InterlockedIncrement(&StartedThreads);
|
||||
#else
|
||||
++StartedThreads; /* thread safe??? -- no, it's not. */
|
||||
++StartedThreads; /* thread safe??? */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
timeval_stamp(&(ptcx->timestat.starttime));
|
||||
D_PRINTF(debugfile, "entering clientLoop\n");
|
||||
|
||||
ret = clientLoop(ptcx); /* do the work */
|
||||
|
||||
timeval_stamp(&(ptcx->timestat.endtime));
|
||||
D_PRINTF(debugfile, "Test run complete\n" );
|
||||
|
||||
/* write current time to debug file */
|
||||
@@ -396,11 +401,15 @@ clientThread(void *targ)
|
||||
}
|
||||
}
|
||||
|
||||
/*sprintf(buf, "NOTICE: client process=%d thread=%d ending\n",
|
||||
ptcx->processnum, ptcx->threadnum);
|
||||
sendOutput(ptcx->ofd, buf);*/
|
||||
|
||||
#ifdef _WIN32
|
||||
/* tell parent we're done */
|
||||
InterlockedIncrement(&FinishedThreads);
|
||||
#else /* _WIN32 */
|
||||
++FinishedThreads; /* thread safe??? -- once again, no */
|
||||
++FinishedThreads; /* thread safe??? */
|
||||
#ifdef USE_PTHREADS
|
||||
if (ptcx->threadnum >= 0)
|
||||
pthread_exit((void *)((ret << 16) | ptcx->threadnum));
|
||||
@@ -636,7 +645,7 @@ summaryThread(void *targ)
|
||||
{
|
||||
ptcx_t ptcxs = (ptcx_t)targ; /* thread contexts */
|
||||
|
||||
D_PRINTF(stderr, "summaryThread starting (ptcxs = 0x%x)...\n", ptcxs);
|
||||
D_PRINTF(stderr, "summaryThread starting...\n");
|
||||
|
||||
/* client threads running...dump periodic stats */
|
||||
while (gn_feedback_secs && (gf_timeexpired < EXIT_FAST)) {
|
||||
@@ -668,7 +677,8 @@ initTcx(ptcx_t ptcx, int ofd, int pnum, int tnum)
|
||||
ptcx->processnum = pnum;
|
||||
ptcx->threadnum = tnum;
|
||||
ptcx->random_seed = (tnum << 16) + getpid();
|
||||
ptcx->cmd_stats = xcalloc(gn_number_of_commands * sizeof(struct cmd_stats));
|
||||
ptcx->cmd_stats =
|
||||
(cmd_stats_t *)mycalloc(sizeof(cmd_stats_t)*gn_number_of_commands);
|
||||
|
||||
/* do PROTO specific init */
|
||||
for (kk = 0; kk < gn_number_of_commands; ++kk) {
|
||||
@@ -684,7 +694,7 @@ void
|
||||
destroyTcx(ptcx_t ptcx)
|
||||
{
|
||||
if (ptcx->cmd_stats) {
|
||||
xfree(ptcx->cmd_stats);
|
||||
free(ptcx->cmd_stats);
|
||||
ptcx->cmd_stats = 0;
|
||||
}
|
||||
}
|
||||
@@ -710,16 +720,8 @@ beginShutdown (void)
|
||||
start threads (if possible/needed) with proper rampup delays
|
||||
wait for threads to end
|
||||
*/
|
||||
|
||||
#ifdef USE_EVENTS
|
||||
extern int gf_use_events;
|
||||
int ev_clientProc(int pnum, int outfd,
|
||||
unsigned int testtime,
|
||||
unsigned int thread_stagger_usec);
|
||||
#endif
|
||||
|
||||
int
|
||||
clientProc(int pnum, int outfd,
|
||||
clientProc(int pnum, SOCKET outfd,
|
||||
unsigned int testtime,
|
||||
unsigned int thread_stagger_usec)
|
||||
{
|
||||
@@ -729,10 +731,6 @@ clientProc(int pnum, int outfd,
|
||||
THREAD_ID summary_tid;
|
||||
int status;
|
||||
|
||||
#ifdef USE_EVENTS
|
||||
if (gf_use_events)
|
||||
return ev_clientProc(pnum, outfd, testtime, thread_stagger_usec);
|
||||
#endif
|
||||
|
||||
bailtime = gt_shutdowntime;
|
||||
|
||||
@@ -754,18 +752,20 @@ clientProc(int pnum, int outfd,
|
||||
|
||||
#if defined(USE_PTHREADS) || defined(_WIN32)
|
||||
if (gn_numthreads > 0) {
|
||||
ptcxs = (ptcx_t)xcalloc(sizeof(tcx_t) * gn_numthreads);
|
||||
ptcxs = (ptcx_t)mycalloc(sizeof(tcx_t) * gn_numthreads);
|
||||
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) {
|
||||
initTcx(&ptcxs[tnum], outfd, pnum, tnum);
|
||||
}
|
||||
|
||||
if ((ret = sysdep_thread_create(&summary_tid, summaryThread,
|
||||
(void *)ptcxs)) != 0) {
|
||||
/*fprintf(stderr, "launching summary\n");*/
|
||||
if ((ret=sysdep_thread_create(&summary_tid, summaryThread,
|
||||
(void *)ptcxs)) != 0) {
|
||||
returnerr(stderr, "client %d: summary thread create failed ret=%d errno=%d: %s\n",
|
||||
pnum, ret, errno, strerror(errno));
|
||||
ptcxs[tnum].tid = 0;
|
||||
}
|
||||
/*fprintf(stderr, "summary should be running...\n");*/
|
||||
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) {
|
||||
if (gf_timeexpired)
|
||||
@@ -823,8 +823,7 @@ clientProc(int pnum, int outfd,
|
||||
returnerr (stderr, "Forcing sockets closed.\n");
|
||||
/* close all client sockets, to force calls to exit */
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) {
|
||||
if (BADSOCKET(ptcxs[tnum].sock))
|
||||
continue;
|
||||
if (BADSOCKET(ptcxs[tnum].sock)) continue;
|
||||
D_PRINTF (stderr, "Closing sock=%d tnum=%d\n",
|
||||
ptcxs[tnum].sock, tnum);
|
||||
set_abortive_close(ptcxs[tnum].sock);
|
||||
@@ -833,8 +832,9 @@ clientProc(int pnum, int outfd,
|
||||
returnerr (stderr, "Forced socket close complete.\n");
|
||||
break;
|
||||
}
|
||||
MS_sleep(1);
|
||||
}
|
||||
MS_sleep(1);
|
||||
}
|
||||
|
||||
|
||||
D_PRINTF (stderr, "Shutdown timeexpired=%d\n", gf_timeexpired);
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
@@ -873,7 +873,7 @@ clientProc(int pnum, int outfd,
|
||||
#endif /* USE_PTHREADS || _WIN32*/
|
||||
{ /* thread un-available or 0 */
|
||||
gn_numthreads = 1;
|
||||
ptcxs = (ptcx_t)xcalloc(sizeof(tcx_t) * gn_numthreads);
|
||||
ptcxs = (ptcx_t)mycalloc(sizeof(tcx_t) * gn_numthreads);
|
||||
|
||||
initTcx(&ptcxs[0], outfd, pnum, -1);
|
||||
|
||||
@@ -891,216 +891,12 @@ clientProc(int pnum, int outfd,
|
||||
clientTimeSummary(ptcxs, gn_numthreads, pnum, outfd);
|
||||
clientBlockSummary(ptcxs, gn_numthreads, pnum, outfd);
|
||||
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) { /* clean up */
|
||||
D_PRINTF(stderr, "client %d: thread %d destroyed\n", pnum, tnum);
|
||||
destroyTcx(&ptcxs[tnum]);
|
||||
#if 0
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) { /* extra reporting */
|
||||
D_PRINTF(stderr, "client %d: thread %d stats\n", pnum, tnum);
|
||||
clientStats(&ptcxs[tnum]);
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "child: %d done\n", pnum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_EVENTS
|
||||
/* version of clientProc which uses event queue */
|
||||
|
||||
/*********************************************************************
|
||||
Things to note:
|
||||
|
||||
The idleTime counter is hopefully correct, but it's a bit tricky --
|
||||
one event will start the timer, and the next is expected to stop it.
|
||||
The invariant is that either ptcx->ev_stats->idle will be NULL or will
|
||||
be started at the beginning of each event function.
|
||||
|
||||
startDelay is strange in that it is sampled from a block that is never
|
||||
executed. However, this block is not counted when figuring
|
||||
statistics, so it won't mess with the results.
|
||||
*********************************************************************/
|
||||
|
||||
#define get_loop_throttle(X) ((X)->throttle)
|
||||
#define get_block_throttle(X) ((X)->throttle)
|
||||
|
||||
static void
|
||||
update_dynamic_throttle(ptcx_t ptcx, mail_command_t * cmd,
|
||||
struct timeval * expected)
|
||||
{
|
||||
struct timeval now;
|
||||
int elapsed;
|
||||
|
||||
if (cmd->loopThrottle == 0 || cmd->throttleFactor == 1)
|
||||
return;
|
||||
|
||||
assert(cmd->throttleFactor != 0);
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&now, expected, &now);
|
||||
elapsed = now.tv_usec / 1000 + now.tv_sec * 1000;
|
||||
if (elapsed > cmd->loopThrottle) {
|
||||
cmd->throttle *= cmd->throttleFactor;
|
||||
D_PRINTF(stderr, "Throttling back %s. New rate = %g\n",
|
||||
cmd->proto->name, cmd->throttle);
|
||||
} else if (elapsed < - cmd->loopThrottle) {
|
||||
cmd->throttle /= cmd->throttleFactor;
|
||||
D_PRINTF(stderr, "Throttling up %s. New rate = %g\n",
|
||||
cmd->proto->name, cmd->throttle);
|
||||
} else {
|
||||
D_PRINTF(stderr,
|
||||
"Not throttling %s (elapsed = %d, throttle = %d). Rate = %g\n",
|
||||
cmd->proto->name, elapsed, cmd->loopThrottle, cmd->throttle);
|
||||
}
|
||||
}
|
||||
|
||||
#include "event.h"
|
||||
ev_queue_t g_eq;
|
||||
|
||||
static int ev_clientThread(void * );
|
||||
static void ev_clientDone(void * );
|
||||
static void client_init(void *arg);
|
||||
static void client_loop(void *arg);
|
||||
|
||||
int
|
||||
ev_clientProc(int pnum, int outfd,
|
||||
unsigned int testtime,
|
||||
unsigned int thread_stagger_usec)
|
||||
{
|
||||
int tnum;
|
||||
int ret;
|
||||
ptcx_t ptcxs; /* thread contexts */
|
||||
THREAD_ID summary_tid;
|
||||
int status;
|
||||
|
||||
|
||||
bailtime = gt_shutdowntime;
|
||||
|
||||
returnerr(stderr, "Child starting\n"); /* get our pid and time printed */
|
||||
D_PRINTF(stderr, "ev_clientProc(%d, %d, %d) starting\n",
|
||||
pnum, testtime, thread_stagger_usec);
|
||||
|
||||
if (testtime <= 0) { /* never happens, checked in main.c */
|
||||
D_PRINTF (stderr, "ABORTING testtime=%d\n", testtime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
setup_signal_handlers ();
|
||||
|
||||
alarm(testtime); /* promptly notice test end */
|
||||
|
||||
D_PRINTF(stderr, "ev_clientProc: outputting summary fmts\n");
|
||||
clientSummaryFormat (pnum, outfd);
|
||||
|
||||
if (gn_numthreads > 0) {
|
||||
ptcxs = (ptcx_t)xcalloc(sizeof(tcx_t) * gn_numthreads);
|
||||
|
||||
D_PRINTF(stderr, "ev_client: initializing tcx's at 0x%x\n", ptcxs);
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) {
|
||||
initTcx(&ptcxs[tnum], outfd, pnum, tnum);
|
||||
}
|
||||
|
||||
/* initialize our event queue */
|
||||
g_eq = ev_queue_create(NULL);
|
||||
D_PRINTF(stderr, "ev_clientProc: created event queue\n");
|
||||
if (g_eq == NULL) {
|
||||
returnerr(stderr, "client %d: can't create event queue.\n", pnum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "ev_client: creating summary thread\n");
|
||||
if ((ret = sysdep_thread_create(&summary_tid, summaryThread,
|
||||
(void *)ptcxs)) != 0) {
|
||||
returnerr(stderr, "client %d: summary thread create failed ret=%d errno=%d: %s\n",
|
||||
pnum, ret, errno, strerror(errno));
|
||||
ptcxs[tnum].tid = 0;
|
||||
}
|
||||
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) {
|
||||
if (gf_timeexpired)
|
||||
break;
|
||||
|
||||
/* sleep between each client thread we try to start */
|
||||
if (tnum && thread_stagger_usec) {
|
||||
MS_usleep(thread_stagger_usec);
|
||||
if (gf_timeexpired)
|
||||
break;
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "client %d: pseudo-thread %d testtime %d\n",
|
||||
pnum, tnum, testtime);
|
||||
|
||||
if (ev_clientThread((void*)&ptcxs[tnum]) < 0) {
|
||||
returnerr(stderr,
|
||||
"client %d: pseudo-thread %d create() failed\n");
|
||||
ptcxs[tnum].tid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for all threads to exit or overtime */
|
||||
while (FinishedThreads < StartedThreads) {
|
||||
int tm = time(0);
|
||||
if (tm > bailtime) {
|
||||
++gf_timeexpired;
|
||||
bailtime += gt_stopinterval;
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
returnerr (stderr, "Client signaling exit, started=%d finished=%d timeexpired=%d\n",
|
||||
StartedThreads, FinishedThreads, gf_timeexpired);
|
||||
kill (0, SIGALRM); /* wake children */
|
||||
}
|
||||
if (ev_queue_destroy(g_eq, gt_stopinterval * 1000) == 0)
|
||||
break;
|
||||
}
|
||||
if (gf_timeexpired >= EXIT_FASTEST) {
|
||||
returnerr (stderr, "Forcing sockets closed.\n");
|
||||
/* close all client sockets, to force calls to exit */
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) {
|
||||
if (BADSOCKET(ptcxs[tnum].sock))
|
||||
continue;
|
||||
D_PRINTF (stderr, "Closing sock=%d tnum=%d\n",
|
||||
ptcxs[tnum].sock, tnum);
|
||||
set_abortive_close(ptcxs[tnum].sock);
|
||||
NETCLOSE(ptcxs[tnum].sock);
|
||||
}
|
||||
returnerr (stderr, "Forced socket close complete.\n");
|
||||
break;
|
||||
}
|
||||
MS_sleep(1);
|
||||
}
|
||||
|
||||
D_PRINTF (stderr, "Shutdown timeexpired=%d\n", gf_timeexpired);
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
gf_timeexpired = EXIT_FAST; /* signal summary thread to exit */
|
||||
returnerr (stderr, "Clean child shutdown\n");
|
||||
} else if (gf_timeexpired >= EXIT_FASTEST) {
|
||||
returnerr (stderr, "Forced child shutdown\n");
|
||||
} else {
|
||||
returnerr (stderr, "Accellerated child shutdown\n");
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "client %d: joining summary thread\n", pnum);
|
||||
if ((ret=sysdep_thread_join(summary_tid, &status)) != 0) {
|
||||
returnerr(stderr,
|
||||
"client %d: summary thread join failed ret=%d errno=%d: %s\n",
|
||||
pnum, ret, errno, strerror(errno));
|
||||
}
|
||||
/* do a summary now in case we hang in joins (needed?) */
|
||||
D_PRINTF(stderr, "client %d: pre-join clientTimeSummary\n", pnum);
|
||||
clientTimeSummary(ptcxs, gn_numthreads, pnum, outfd);
|
||||
|
||||
} else { /* thread un-available or 0 */
|
||||
gn_numthreads = 1;
|
||||
ptcxs = (ptcx_t)xcalloc(sizeof(tcx_t) * gn_numthreads);
|
||||
|
||||
initTcx(&ptcxs[0], outfd, pnum, -1);
|
||||
|
||||
D_PRINTF(stderr, "client %d: testtime: %d\n", pnum);
|
||||
|
||||
/* set initial data point */
|
||||
D_PRINTF(stderr, "client %d: initial clientTimeSummary\n", 0);
|
||||
clientTimeSummary(ptcxs, gn_numthreads, pnum, outfd);
|
||||
|
||||
clientThread(&ptcxs[0]);
|
||||
}
|
||||
|
||||
/* final time summary feedback */
|
||||
D_PRINTF(stderr, "client %d: final summaries\n", 0);
|
||||
clientTimeSummary(ptcxs, gn_numthreads, pnum, outfd);
|
||||
clientBlockSummary(ptcxs, gn_numthreads, pnum, outfd);
|
||||
#endif
|
||||
|
||||
for (tnum = 0; tnum < gn_numthreads; ++tnum) { /* clean up */
|
||||
D_PRINTF(stderr, "client %d: thread %d destroyed\n", pnum, tnum);
|
||||
@@ -1110,282 +906,3 @@ ev_clientProc(int pnum, int outfd,
|
||||
D_PRINTF(stderr, "child: %d done\n", pnum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
choose_cmd()
|
||||
{
|
||||
int comm_index = 0;
|
||||
if (gn_number_of_commands > 1) {
|
||||
int ran_number;
|
||||
/* Handle the weighted distribution of commands */
|
||||
ran_number = (RANDOM() % gn_total_weight);
|
||||
|
||||
/* loop through pages, find correct one
|
||||
* while ran_number is positive, decrement it
|
||||
* by the weight of the current page
|
||||
* example: ran_number is 5, pages have weights of 10 and 10
|
||||
* first iteration comm_index = 0, ran_number = -5
|
||||
* iteration halted, comm_index = 0
|
||||
*/
|
||||
comm_index = -1;
|
||||
while (ran_number >= 0) {
|
||||
comm_index++;
|
||||
ran_number -= g_loaded_comm_list[comm_index].weight;
|
||||
}
|
||||
}
|
||||
return comm_index;
|
||||
}
|
||||
|
||||
static int
|
||||
ev_clientThread(void *targ)
|
||||
{
|
||||
time_t currentTime;
|
||||
struct tm *tmptm;
|
||||
char timeStamp[DATESTAMP_LEN];
|
||||
tcx_t *ptcx = (ptcx_t)targ;
|
||||
|
||||
if (clientInit(ptcx)) { /* should never fail */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gn_debug) {
|
||||
/* write current time to debug file */
|
||||
time(¤tTime);
|
||||
tmptm = localtime(¤tTime);
|
||||
strftime(timeStamp, DATESTAMP_LEN, "%Y%m%d%H%M%S", tmptm);
|
||||
D_PRINTF(debugfile, "Time Stamp: %s\n", timeStamp);
|
||||
D_PRINTF(debugfile, "mailstone run dateStamp=%s\n", gs_dateStamp);
|
||||
}
|
||||
|
||||
++StartedThreads;
|
||||
|
||||
ptcx->blockCount = 0;
|
||||
|
||||
ptcx->ev_stats = NULL; /* don't update stats in client_init */
|
||||
client_init(ptcx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ev_clientDone(void *targ)
|
||||
{
|
||||
time_t currentTime;
|
||||
struct tm *tmptm;
|
||||
char timeStamp[DATESTAMP_LEN];
|
||||
tcx_t *ptcx = (ptcx_t)targ;
|
||||
|
||||
/* count outstanding idle time */
|
||||
if (ptcx->ev_stats != NULL)
|
||||
event_stop(ptcx, &ptcx->ev_stats->idle);
|
||||
|
||||
D_PRINTF(debugfile, "Test run complete\n" );
|
||||
|
||||
/* write current time to debug file */
|
||||
time(¤tTime);
|
||||
tmptm = localtime(¤tTime);
|
||||
strftime(timeStamp, DATESTAMP_LEN, "%Y%m%d%H%M%S", tmptm);
|
||||
D_PRINTF(debugfile, "Time Stamp: %s\n", timeStamp);
|
||||
|
||||
if (gn_record_telemetry && (ptcx->logfile > 0)) {
|
||||
close(ptcx->logfile);
|
||||
ptcx->logfile = -1;
|
||||
}
|
||||
|
||||
D_PRINTF(debugfile, "client exiting.\n" );
|
||||
|
||||
if (gn_debug && ptcx->dfile) {
|
||||
fflush(ptcx->dfile);
|
||||
if (ptcx->dfile != stderr) {
|
||||
fclose(ptcx->dfile);
|
||||
ptcx->dfile = stderr;
|
||||
}
|
||||
}
|
||||
|
||||
++FinishedThreads;
|
||||
}
|
||||
|
||||
void
|
||||
add_msec(struct timeval * tv, int ms)
|
||||
{
|
||||
tv->tv_sec += ms / 1000;
|
||||
tv->tv_usec += 1000 * (ms % 1000);
|
||||
if (tv->tv_usec >= 1000000) {
|
||||
tv->tv_sec++;
|
||||
tv->tv_usec -= 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** client_init -- perform an init action.
|
||||
**
|
||||
** Note:
|
||||
** Test run completion cannot be signaled by closing the
|
||||
** event queue, since a "nice" shutdown still demands
|
||||
** various logout actions.
|
||||
*/
|
||||
|
||||
static void client_init2(void * );
|
||||
|
||||
static void
|
||||
client_init(void *arg)
|
||||
{
|
||||
ptcx_t ptcx = (ptcx_t)arg;
|
||||
cmd_stats_t * old_stats = ptcx->ev_stats;
|
||||
int comm_index;
|
||||
|
||||
if (gf_timeexpired >= EXIT_SOON) {
|
||||
/* do something here? */
|
||||
fprintf(stderr, "client_init(): after test-end.\n");
|
||||
++FinishedThreads;
|
||||
return;
|
||||
}
|
||||
|
||||
comm_index = choose_cmd();
|
||||
ptcx->ev_comm = &g_loaded_comm_list[comm_index];
|
||||
ptcx->ev_stats = &(ptcx->cmd_stats[comm_index]);
|
||||
|
||||
/* Figure out when to do second half of client_init() */
|
||||
if (old_stats == NULL) {
|
||||
/* first time => use startDelay */
|
||||
int start_delay = sample(ptcx->ev_comm->startDelay);
|
||||
if (start_delay < 0) {
|
||||
fprintf(stderr, "eek: start-delay < 0\n");
|
||||
start_delay = 0;
|
||||
}
|
||||
if (ev_after(g_eq, start_delay, client_init2, (void*)ptcx) < 0)
|
||||
/* error */;
|
||||
} else {
|
||||
/* do protocol-independent statistics */
|
||||
++ptcx->connectCount;
|
||||
++ptcx->blockCount;
|
||||
event_stop(ptcx, &old_stats->idle);
|
||||
client_init2((void*)ptcx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** client_init2 -- second half of client_init()
|
||||
*/
|
||||
|
||||
static void
|
||||
client_init2(void * arg)
|
||||
{
|
||||
ptcx_t ptcx = (ptcx_t)arg;
|
||||
struct timeval next;
|
||||
|
||||
/*
|
||||
** figure out when we should do the next action and next block,
|
||||
** but don't actually schedule them until we finish the current
|
||||
** one. This guarantees that actions are always performed in
|
||||
** order.
|
||||
*/
|
||||
|
||||
ptcx->ev_stats->totalcommands++; /* track command blocks trys */
|
||||
|
||||
gettimeofday(&next, NULL);
|
||||
ptcx->ev_next.tv_sec = next.tv_sec;
|
||||
ptcx->ev_next.tv_usec = next.tv_usec;
|
||||
ptcx->ev_loop = ptcx->ev_comm->numLoops;
|
||||
|
||||
/* time for next block */
|
||||
add_msec(&ptcx->ev_next, (get_block_throttle(ptcx->ev_comm)
|
||||
* sample(ptcx->ev_comm->blockTime)));
|
||||
|
||||
/* time for next unit of work in this block */
|
||||
add_msec(&next, sample(ptcx->ev_comm->idleTime));
|
||||
|
||||
/* run the init function, and schedule the first loop (or end) */
|
||||
ptcx->ev_state = (*(ptcx->ev_comm->proto->cmdStart)) (ptcx, ptcx->ev_comm,
|
||||
ptcx->ev_stats);
|
||||
|
||||
if (ptcx->ev_state == NULL) {
|
||||
D_PRINTF(stderr, "do_command Start failed\n");
|
||||
event_start(ptcx, &ptcx->ev_stats->idle);
|
||||
ev_at(g_eq, &ptcx->ev_next, client_init, (void*)ptcx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check to see if we've scheduled enough blocks */
|
||||
if (gn_maxBlockCnt && (ptcx->blockCount >= gn_maxBlockCnt)) {
|
||||
D_PRINTF (debugfile, "Saw enough loops %d, exiting\n",
|
||||
ptcx->blockCount);
|
||||
beginShutdown (); /* indicate early exit */
|
||||
}
|
||||
|
||||
event_start(ptcx, &ptcx->ev_stats->idle);
|
||||
ev_at(g_eq, &next, client_loop, (void*)ptcx);
|
||||
}
|
||||
|
||||
static void
|
||||
client_loop(void *arg)
|
||||
{
|
||||
ptcx_t ptcx = (ptcx_t)arg;
|
||||
|
||||
assert(ptcx);
|
||||
assert(ptcx->ev_comm);
|
||||
assert(ptcx->ev_comm->proto);
|
||||
|
||||
event_stop(ptcx, &ptcx->ev_stats->idle);
|
||||
|
||||
/* check for rude shutdown: */
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
fprintf(stderr, "%s: forced shutdown.\n", ptcx->ev_comm->proto->name);
|
||||
ev_clientDone(arg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptcx->ev_loop == 0) {
|
||||
/* run end function */
|
||||
if (ptcx->ev_comm->proto->cmdEnd)
|
||||
(*(ptcx->ev_comm->proto->cmdEnd))(ptcx, ptcx->ev_comm,
|
||||
ptcx->ev_stats, ptcx->ev_state);
|
||||
|
||||
if (gf_timeexpired >= EXIT_SOON) {
|
||||
fprintf(stderr, "%s: finished.\n", ptcx->ev_comm->proto->name);
|
||||
ev_clientDone(arg);
|
||||
return;
|
||||
}
|
||||
/* schedule next item */
|
||||
event_start(ptcx, &ptcx->ev_stats->idle);
|
||||
ev_at(g_eq, &ptcx->ev_next, client_init, arg);
|
||||
} else {
|
||||
/* run loop function */
|
||||
struct timeval next;
|
||||
int ret = 0;
|
||||
|
||||
assert (ptcx->ev_comm);
|
||||
assert (ptcx->ev_stats);
|
||||
assert (ptcx->ev_state);
|
||||
|
||||
gettimeofday(&next, NULL);
|
||||
add_msec(&next, get_loop_throttle(ptcx->ev_comm) * sample(ptcx->ev_comm->loopDelay));
|
||||
if (ptcx->ev_comm->proto->cmdLoop)
|
||||
ret = (*(ptcx->ev_comm->proto->cmdLoop))(ptcx,
|
||||
ptcx->ev_comm,
|
||||
ptcx->ev_stats,
|
||||
ptcx->ev_state);
|
||||
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
fprintf(stderr, "%s: forced shutdown.",
|
||||
ptcx->ev_comm->proto->name);
|
||||
ev_clientDone(arg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gf_timeexpired >= EXIT_SOON || ret != 0) {
|
||||
fprintf(stderr, "%s: finishing (%d remaining loops).\n",
|
||||
ptcx->ev_comm->proto->name, ptcx->ev_loop);
|
||||
ptcx->ev_loop = 0; /* do end function */
|
||||
}
|
||||
else {
|
||||
ptcx->ev_loop--; /* do next loop (or end) */
|
||||
/* only update throttling if loop succeeded */
|
||||
update_dynamic_throttle(ptcx, ptcx->ev_comm, &next);
|
||||
}
|
||||
event_start(ptcx, &ptcx->ev_stats->idle);
|
||||
ev_at(g_eq, &next, client_loop, arg);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_EVENTS */
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _constants_h
|
||||
#define _constants_h
|
||||
|
||||
/*
|
||||
** LIMITS
|
||||
*/
|
||||
|
||||
#define MAX_ACCEPT_SECS 180 /* maximum time master will wait for listen() */
|
||||
#define LINE_BUFSIZE 4096
|
||||
#define MAX_USERNAME_LEN 32
|
||||
#define MAX_MAILADDR_LEN 64
|
||||
#define MAX_COMMAND_LEN 1024
|
||||
#define MAX_RESPONSE_LEN 1024
|
||||
#define MAX_ERRORMSG_LEN 256
|
||||
#define DATESTAMP_LEN 40
|
||||
|
||||
#define MAX_IMAP_FOLDERNAME_LEN 256
|
||||
#define MAX_SEARCH_PATTERN_LEN 256
|
||||
|
||||
#define MAX_HTTP_COMMAND_LEN 1024
|
||||
|
||||
/* TODO make these dynamic. For now just use big buffers */
|
||||
#define SIZEOF_EVENTTEXT 150 /* report text from a single timer */
|
||||
#define SIZEOF_RQSTSTATSTEXT 2048 /* report text from all timers */
|
||||
#define SIZEOF_SUMMARYTEXT 8192 /* report text from all protocols */
|
||||
|
||||
/*
|
||||
** PORTS
|
||||
*/
|
||||
|
||||
#define SMTP_PORT 25
|
||||
#define POP3_PORT 110
|
||||
#define IMAP4_PORT 143
|
||||
#define HTTP_PORT 80
|
||||
#define WMAP_PORT 80
|
||||
#define WEBMAIL_PORT 1066
|
||||
|
||||
/*
|
||||
** time-related
|
||||
*/
|
||||
#define USECINSEC 1000000
|
||||
#define MSECINSEC 1000
|
||||
|
||||
#define SECS_2_USECS(x) ((x) * USECINSEC)
|
||||
#define USECS_2_SECS(x) ((x) / USECINSEC)
|
||||
|
||||
/*
|
||||
** Miscellany
|
||||
*/
|
||||
|
||||
#define CRLF "\r\n"
|
||||
|
||||
#endif /* _constants_h */
|
||||
@@ -1,461 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include "event.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/*
|
||||
** EVENT.C -- event queue with dynamic thread-pool
|
||||
*/
|
||||
|
||||
struct ev_queue_params EV_DEFAULTS = { 1000, 4, 8 };
|
||||
|
||||
#if 0
|
||||
# define EV_DPRINTF(X) fprintf X /* debugging output */
|
||||
# define EV_DEBUG(X) X
|
||||
#else
|
||||
# define EV_DPRINTF(X) (void)0
|
||||
# define EV_DEBUG(X) (void)0
|
||||
#endif
|
||||
|
||||
typedef struct Event
|
||||
{
|
||||
ev_func_t func;
|
||||
void * arg;
|
||||
struct timeval time;
|
||||
} Event;
|
||||
|
||||
#if 0
|
||||
typedef struct IOEvent
|
||||
{
|
||||
ev_io_func_t func;
|
||||
void * arg;
|
||||
struct pollfd pfd;
|
||||
};
|
||||
#endif /* 0 */
|
||||
|
||||
typedef struct ev_qelt
|
||||
{
|
||||
struct ev_qelt * next;
|
||||
Event e;
|
||||
} ev_qelt;
|
||||
|
||||
struct ev_Queue
|
||||
{
|
||||
/* tunable parameters */
|
||||
struct ev_queue_params p;
|
||||
|
||||
/* state */
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t available, finished;
|
||||
int waiting_threads, threads;
|
||||
int finish;
|
||||
|
||||
ev_qelt * head;
|
||||
};
|
||||
|
||||
/* internal functions */
|
||||
static int ev_queue_create_worker(ev_queue_t );
|
||||
static void *ev_queue_worker(void*);
|
||||
|
||||
ev_queue_t
|
||||
ev_queue_create(ev_queue_params_t params)
|
||||
{
|
||||
ev_queue_t q = XALLOC(struct ev_Queue);
|
||||
int i;
|
||||
EV_DEBUG(extern int errno);
|
||||
|
||||
pthread_mutex_init(&(q->lock), NULL);
|
||||
pthread_cond_init(&(q->available), NULL);
|
||||
pthread_cond_init(&(q->finished), NULL);
|
||||
q->waiting_threads = q->threads = 0;
|
||||
q->finish = 0;
|
||||
q->head = NULL;
|
||||
|
||||
if (params == NULL)
|
||||
{
|
||||
params = &EV_DEFAULTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (params->lowat == EV_Q_UNSPEC)
|
||||
params->lowat = EV_DEFAULTS.lowat;
|
||||
if (params->hiwat == EV_Q_UNSPEC)
|
||||
params->hiwat = EV_DEFAULTS.hiwat;
|
||||
if (params->min_sleep == EV_Q_UNSPEC)
|
||||
params->min_sleep = EV_DEFAULTS.min_sleep;
|
||||
}
|
||||
|
||||
memcpy(&q->p, params, sizeof(struct ev_queue_params));
|
||||
EV_DPRINTF((stderr, "ev_queue: lowat = %d, hiwat = %d, minsl = %d\n",
|
||||
q->p.lowat, q->p.hiwat, q->p.min_sleep));
|
||||
pthread_mutex_lock(&(q->lock));
|
||||
for (i = 0; i < q->p.lowat; i++)
|
||||
if (ev_queue_create_worker(q) < 0)
|
||||
{
|
||||
EV_DPRINTF((stderr, "Failed to create worker: %s\n",
|
||||
strerror(errno)));
|
||||
assert(0);
|
||||
}
|
||||
pthread_mutex_unlock(&(q->lock));
|
||||
EV_DPRINTF((stderr, "Created event queue\n"));
|
||||
return q;
|
||||
}
|
||||
|
||||
int
|
||||
ev_queue_destroy(q, msec)
|
||||
ev_queue_t q;
|
||||
unsigned msec;
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
q->finish = 1;
|
||||
pthread_mutex_lock(&(q->lock));
|
||||
pthread_cond_broadcast(&(q->available));
|
||||
EV_DPRINTF((stderr, "Waiting for workers to finish\n"));
|
||||
if (msec == 0)
|
||||
{
|
||||
pthread_cond_wait(&(q->finished), &(q->lock));
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timespec ts;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
tv.tv_usec += msec * 1000;
|
||||
if (tv.tv_usec > 1000000)
|
||||
{
|
||||
tv.tv_sec += tv.tv_usec / 1000000;
|
||||
tv.tv_usec %= 1000000;
|
||||
}
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = msec * 1000;
|
||||
if (pthread_cond_timedwait(&(q->finished), &(q->lock), &ts) ==
|
||||
ETIMEDOUT)
|
||||
{
|
||||
/*
|
||||
** some thread(s) took too long. Do not
|
||||
** destroy the queue yet.
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
pthread_cond_destroy(&(q->available));
|
||||
pthread_cond_destroy(&(q->finished));
|
||||
pthread_mutex_unlock(&(q->lock));
|
||||
|
||||
pthread_mutex_destroy(&(q->lock));
|
||||
EV_DPRINTF((stderr, "Queue destroyed\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ev_after(q, millis, func, arg)
|
||||
ev_queue_t q;
|
||||
int millis;
|
||||
ev_func_t func;
|
||||
void * arg;
|
||||
{
|
||||
struct timeval t;
|
||||
assert(millis >= 0);
|
||||
gettimeofday(&t, NULL);
|
||||
t.tv_sec += millis/1000;
|
||||
t.tv_usec += (millis % 1000) * 1000;
|
||||
if (t.tv_usec >= 1000000)
|
||||
{
|
||||
t.tv_usec -= 1000000;
|
||||
t.tv_sec++;
|
||||
}
|
||||
return ev_at(q, &t, func, arg);
|
||||
}
|
||||
|
||||
int
|
||||
ev_at(q, time, func, arg)
|
||||
ev_queue_t q;
|
||||
struct timeval *time;
|
||||
ev_func_t func;
|
||||
void * arg;
|
||||
{
|
||||
int d_place = 0;
|
||||
int ret = 0;
|
||||
ev_qelt **elt;
|
||||
ev_qelt *new_elt;
|
||||
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
now.tv_usec -= 100000;
|
||||
if (now.tv_usec < 0)
|
||||
{
|
||||
now.tv_sec--;
|
||||
now.tv_usec += 1000000;
|
||||
}
|
||||
|
||||
if (q->finish) /* don't schedule after finish. */
|
||||
return -1;
|
||||
|
||||
new_elt = XALLOC(ev_qelt);
|
||||
new_elt->e.time.tv_sec = time->tv_sec;
|
||||
new_elt->e.time.tv_usec = time->tv_usec;
|
||||
new_elt->e.func = func;
|
||||
new_elt->e.arg = arg;
|
||||
|
||||
#if 0
|
||||
if (timercmp(time, &now, <=))
|
||||
fprintf(stderr, "Warning: scheduling event %p > 100ms ago\n",
|
||||
new_elt);
|
||||
#endif /* 0 */
|
||||
|
||||
pthread_mutex_lock(&(q->lock));
|
||||
|
||||
/* find new_elt's place in queue */
|
||||
elt = &(q->head);
|
||||
while (*elt != NULL && timercmp(time, &((*elt)->e.time), >))
|
||||
{
|
||||
elt = &((*elt)->next);
|
||||
d_place++;
|
||||
}
|
||||
|
||||
new_elt->next = *elt;
|
||||
*elt = new_elt;
|
||||
EV_DPRINTF((stderr, "Scheduled event %p\n", new_elt));
|
||||
|
||||
/*
|
||||
** wake up workers if the queue was empty, or if this next
|
||||
** event might need immediate execution.
|
||||
*/
|
||||
if(q->head->next == NULL || q->head == new_elt)
|
||||
pthread_cond_signal(&(q->available));
|
||||
|
||||
pthread_mutex_unlock(&(q->lock));
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
ev_io(q, fd, events, func, arg)
|
||||
ev_queue_t q;
|
||||
int fd;
|
||||
short events;
|
||||
ev_func_t func;
|
||||
void * arg;
|
||||
{
|
||||
/* NOT IMPLEMENTED */
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ev_queue_create_worker(q)
|
||||
ev_queue_t q;
|
||||
{
|
||||
pthread_t th;
|
||||
int ret;
|
||||
extern int errno;
|
||||
|
||||
if (q->finish)
|
||||
{
|
||||
EV_DPRINTF((stderr,
|
||||
"Attempt to create worker in finishing queue\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = pthread_create(&th, NULL,
|
||||
&ev_queue_worker, (void*)q) != 0))
|
||||
{
|
||||
int error = errno;
|
||||
fprintf(stderr, "Can't create queue worker (%d): %s\n",
|
||||
ret, strerror(error));
|
||||
return -1;
|
||||
}
|
||||
if (pthread_detach(th) != 0)
|
||||
{
|
||||
fprintf(stderr, "Can't detach queue worker: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void*
|
||||
ev_queue_worker(ptr)
|
||||
void * ptr;
|
||||
{
|
||||
ev_queue_t q = (ev_queue_t)ptr;
|
||||
EV_DEBUG(pthread_t me = pthread_self());
|
||||
|
||||
EV_DPRINTF((stderr, "%ld: New worker: threads = %d\n", me, q->threads));
|
||||
|
||||
pthread_mutex_lock(&(q->lock));
|
||||
q->threads++;
|
||||
|
||||
while (!q->finish)
|
||||
{
|
||||
ev_qelt *e;
|
||||
int sleeptime;
|
||||
struct timeval now;
|
||||
|
||||
if (q->head == NULL)
|
||||
{
|
||||
EV_DPRINTF((stderr, "%ld sleeping -- no events\n",
|
||||
me));
|
||||
/* check to see if too many idle threads */
|
||||
if (++q->waiting_threads > q->p.hiwat)
|
||||
{
|
||||
--q->waiting_threads;
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_cond_wait(&(q->available), &(q->lock));
|
||||
|
||||
if (--q->waiting_threads < q->p.lowat)
|
||||
ev_queue_create_worker(q);
|
||||
}
|
||||
else /* q->head != NULL */
|
||||
{
|
||||
EV_DPRINTF((stderr, "%ld: Head is %p\n", me, q->head));
|
||||
/* some events -- see if they're ready */
|
||||
e = q->head;
|
||||
gettimeofday(&now, NULL);
|
||||
sleeptime = (e->e.time.tv_sec - now.tv_sec) * 1000000
|
||||
+ (e->e.time.tv_usec - now.tv_usec);
|
||||
|
||||
if (sleeptime < q->p.min_sleep)
|
||||
{
|
||||
if (sleeptime < 0)
|
||||
{
|
||||
EV_DPRINTF((stderr,
|
||||
"%ld Warning: %p late by %d usec\n",
|
||||
me, e, -sleeptime));
|
||||
}
|
||||
/* close enough -- execute it. */
|
||||
q->head = q->head->next;
|
||||
pthread_mutex_unlock(&(q->lock));
|
||||
|
||||
EV_DPRINTF((stderr, "%ld Executing %p\n",
|
||||
me, e));
|
||||
(e->e.func)(e->e.arg);
|
||||
xfree(e);
|
||||
|
||||
/* reacquire lock and keep going */
|
||||
pthread_mutex_lock(&(q->lock));
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
/* sleep */
|
||||
/* check to see if too many idle threads */
|
||||
if (++q->waiting_threads > q->p.hiwat)
|
||||
{
|
||||
--q->waiting_threads;
|
||||
break;
|
||||
}
|
||||
ts.tv_nsec = e->e.time.tv_usec * 1000
|
||||
- q->p.min_sleep * 1000;
|
||||
ts.tv_sec = e->e.time.tv_sec;
|
||||
EV_DPRINTF((stderr, "%ld: sleeping until %ld.%.9ld\n",
|
||||
me, ts.tv_sec, ts.tv_nsec));
|
||||
pthread_cond_timedwait(&(q->available),
|
||||
&(q->lock),
|
||||
&ts);
|
||||
if (--q->waiting_threads < q->p.lowat)
|
||||
ev_queue_create_worker(q);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* done */
|
||||
if (--q->threads == 0)
|
||||
{
|
||||
EV_DPRINTF((stderr, "%ld: No more threads -- done", me));
|
||||
pthread_cond_signal(&(q->finished));
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&(q->lock));
|
||||
EV_DPRINTF((stderr, "%ld: Worker finished\n", me));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef EV_Q_TEST
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void *
|
||||
xalloc(size)
|
||||
size_t size;
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
assert(ret != NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct ev_Queue myqueue;
|
||||
|
||||
static void
|
||||
print_time(arg)
|
||||
void * arg;
|
||||
{
|
||||
int nleft = (int)arg;
|
||||
time_t t = time(0);
|
||||
if (nleft > 0)
|
||||
ev_after(&myqueue, 2000, print_time, (void*)nleft);
|
||||
fprintf(stderr, "[%d] time is %s\n", nleft, ctime(&t));
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char * argv[];
|
||||
{
|
||||
int nthings = atoi(argv[1]);
|
||||
ev_queue_init(&myqueue);
|
||||
while (nthings-- > 0)
|
||||
{
|
||||
ev_after(&myqueue, 1000*nthings,
|
||||
print_time, (void*)nthings);
|
||||
}
|
||||
sleep(10);
|
||||
ev_queue_destroy(&myqueue);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif /* EV_Q_TEST */
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _event_h
|
||||
#define _event_h
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
typedef struct ev_Queue * ev_queue_t;
|
||||
|
||||
typedef struct ev_queue_params
|
||||
{
|
||||
int min_sleep; /* smallest time to bother to sleep (usec) */
|
||||
int lowat; /* minimum number of free threads */
|
||||
int hiwat; /* maximum number of free threads */
|
||||
} *ev_queue_params_t;
|
||||
|
||||
#define EV_Q_UNSPEC -1 /* unspecified parameter value (use defualt) */
|
||||
|
||||
typedef void (*ev_func_t)(void*);
|
||||
typedef void (*ev_io_func_t)(int, short, void *);
|
||||
|
||||
/*
|
||||
** EV_QUEUE_CREATE -- Allocate and initialize a new event queue.
|
||||
**
|
||||
** Parameters:
|
||||
** params -- pointer to queue parameters, or NULL to use
|
||||
** defaults.
|
||||
**
|
||||
** Returns:
|
||||
** new ev_queue_t or NULL on failure
|
||||
*/
|
||||
|
||||
extern ev_queue_t
|
||||
ev_queue_create(ev_queue_params_t params);
|
||||
|
||||
/*
|
||||
** EV_QUEUE_DESTROY -- Flush and destroy an event queue.
|
||||
**
|
||||
** ev_queue_destroy() prevents new events from being scheduled,
|
||||
** executes all pending events, then frees all resources
|
||||
** associated with the queue.
|
||||
**
|
||||
** Parameters:
|
||||
** q -- the event queue to destroy.
|
||||
** msec -- if non-zero, timeout on waiting for worker threads.
|
||||
**
|
||||
** Returns:
|
||||
** 0 on success, or -1 on failure.
|
||||
*/
|
||||
|
||||
extern int
|
||||
ev_queue_destroy(ev_queue_t q, unsigned msec);
|
||||
|
||||
/*
|
||||
** EV_AFTER -- schedule an event relative to now
|
||||
**
|
||||
** Parameters:
|
||||
** q -- the queue.
|
||||
** time -- how long from now to schedule event (msec.).
|
||||
** func -- function to call.
|
||||
** arg -- what to pass to function.
|
||||
**
|
||||
** Returns:
|
||||
** 0 on success, or -1 on failure.
|
||||
*/
|
||||
|
||||
extern int
|
||||
ev_after(ev_queue_t q, int time, ev_func_t func, void * arg);
|
||||
|
||||
/*
|
||||
** EV_AT -- schedule an event at an absolute time
|
||||
**
|
||||
** Parameters:
|
||||
** q -- the queue.
|
||||
** time -- when to schedule event.
|
||||
** func -- function to call.
|
||||
** arg -- what to pass to function.
|
||||
**
|
||||
** Returns:
|
||||
** 0 on success, or -1 on failure.
|
||||
**
|
||||
** Note:
|
||||
** time can be in the past, in which case the event will
|
||||
** be scheduled for immediate execution.
|
||||
*/
|
||||
|
||||
extern int
|
||||
ev_at(ev_queue_t q, struct timeval * time, ev_func_t func, void * arg);
|
||||
|
||||
/*
|
||||
** EV_IO -- schedule a handler for asynchronous I/O completion.
|
||||
**
|
||||
** Parameters:
|
||||
** q -- the queue.
|
||||
** fd -- file descriptor to wait for.
|
||||
** events -- events for which to poll.
|
||||
** func -- function to call.
|
||||
** arg -- what to pass to function.
|
||||
**
|
||||
** Returns:
|
||||
** 0 on success, or -1 on failure.
|
||||
**
|
||||
*/
|
||||
|
||||
extern int
|
||||
ev_io(ev_queue_t q, int fd, short events, ev_io_func_t func, void * arg);
|
||||
|
||||
#endif /* _event_h */
|
||||
@@ -1,519 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifdef AUTOGEN
|
||||
#include <assert.h>
|
||||
#include "generate.h"
|
||||
#include "idle.h"
|
||||
#include "xalloc.h"
|
||||
#include "checksum.h"
|
||||
|
||||
#define GEN_MSGIDS
|
||||
|
||||
/*
|
||||
** Data used for generated messages.
|
||||
*/
|
||||
|
||||
/* headers to always put on a messages */
|
||||
#ifdef GEN_MSGIDS
|
||||
/* pass through printf(X, starttime.tv_sec, procnum, threadnum, msgnum) */
|
||||
static char GEN_HDRS[] =
|
||||
"From: mailstone-autogen" CRLF
|
||||
"To: test-user" CRLF
|
||||
"Message-ID: <p%d.t%d.m%d@mstone-generated>" CRLF
|
||||
"Date: %s" CRLF
|
||||
"Subject: benchmark message (auto-generated)" CRLF;
|
||||
#else
|
||||
static char GEN_HDRS[] =
|
||||
"From: mailstone-autogen" CRLF
|
||||
"To: test-user" CRLF
|
||||
"Message-ID: <12345678.123@nowhere>" CRLF
|
||||
"Date: Fri, 10 Jul 1999 00:00:00 -0800" CRLF
|
||||
"Subject: benchmark message (auto-generated)" CRLF;
|
||||
#endif
|
||||
static int N_GEN_HDRS = 5;
|
||||
|
||||
/* format to use for added headers (%d replaced by header index) */
|
||||
static char GEN_HDRFORMAT[] = "X-generated-%d: value of generated header" CRLF;
|
||||
|
||||
/* line of generated mesage */
|
||||
static char GEN_LINE[] =
|
||||
"012345678901234567890123456789012345678901234567890123456789" CRLF;
|
||||
|
||||
/* end-of-message sequence */
|
||||
static char EOM[] = CRLF "." CRLF;
|
||||
|
||||
/* boundary string format */
|
||||
#define MIME_BOUNDARY "autogen-boundary-string:%d"
|
||||
|
||||
/* attachment file name */
|
||||
#define MIME_FILE "foo.dat"
|
||||
|
||||
/* attachment MIME type */
|
||||
#define MIME_TYPE "application/x-generated"
|
||||
|
||||
/* plain text before first MIME subpart */
|
||||
#define MIME_WARNING "This message is MIME." CRLF
|
||||
|
||||
/* section boundary (subjected to printf(X, int)) */
|
||||
static char MIME_SEPARATOR[] =
|
||||
CRLF
|
||||
"--" MIME_BOUNDARY CRLF;
|
||||
|
||||
/* End of MIME message (passed through printf(X, int)) */
|
||||
static char MIME_TERMINATOR[] =
|
||||
CRLF
|
||||
"--" MIME_BOUNDARY "--" CRLF;
|
||||
|
||||
/* multipart header (passed through printf(X, int)). */
|
||||
static char MIME_MULTIPART_HDR[] =
|
||||
"MIME-Version: 1.0" CRLF
|
||||
"Content-Type: multipart/mixed;" CRLF
|
||||
" boundary=\"" MIME_BOUNDARY "\"" CRLF;
|
||||
|
||||
/* multipart header (passed through printf(X, char *, char *)). */
|
||||
static char MIME_PART_HDR[] =
|
||||
"Content-Type: %s" CRLF
|
||||
"Content-Transfer-Encoding: base64" CRLF
|
||||
"Content-Disposition: attachment; filename=\"%s\"" CRLF;
|
||||
|
||||
/* actual body blocksize == gen_blksize - gen_blksize % strlen(GEN_LINE) */
|
||||
static int gen_bodylen = -1;
|
||||
static int gen_blksize = 8192;
|
||||
|
||||
/* generated body data */
|
||||
static char *gen_body = NULL;
|
||||
|
||||
#define GEN_WRITE(BUF, LEN) (retryWrite(ptcx, ptcx->sock, (BUF), (LEN)))
|
||||
|
||||
#define GEN_CONSTWRITE(BUF) GEN_WRITE(BUF, strlen(BUF))
|
||||
|
||||
#define DIE_UNLESS(X) do { if((X) < 0) \
|
||||
{ \
|
||||
fprintf(stderr, "generateMessage: Error: `" #X "' failed: %s\n", \
|
||||
strerror(errno)); \
|
||||
return -1; \
|
||||
} } while (0)
|
||||
|
||||
#define WRITE_CRLF DIE_UNLESS(GEN_CONSTWRITE(CRLF)); nwritten += strlen(CRLF)
|
||||
|
||||
/*
|
||||
** Prototypes
|
||||
*/
|
||||
|
||||
void gen_init();
|
||||
static int gen_write_body(ptcx_t ptcx, int ntowrite, struct checksum_t *cs);
|
||||
static int gen_write_hdrs(ptcx_t ptcx, int nhdrs);
|
||||
static int mime_separator(ptcx_t ptcx, int n, int term, struct checksum_t *cs);
|
||||
static int mime_multipart_headers(ptcx_t ptcx, int n, struct checksum_t *cs);
|
||||
static int mime_part_headers(ptcx_t ptcx, char *type, char *name,
|
||||
struct checksum_t *cs);
|
||||
|
||||
|
||||
/*
|
||||
** GEN_INIT -- initialize body data buffer.
|
||||
*/
|
||||
|
||||
void
|
||||
gen_init()
|
||||
{
|
||||
int i;
|
||||
int glsize = strlen(GEN_LINE);
|
||||
int n = gen_blksize / glsize;
|
||||
gen_bodylen = n*glsize;
|
||||
gen_body = xalloc(gen_bodylen);
|
||||
|
||||
for(i=0; i < n; i++)
|
||||
memcpy(gen_body + i*glsize,
|
||||
GEN_LINE,
|
||||
glsize);
|
||||
}
|
||||
|
||||
/*
|
||||
** GEN_WRITE_BODY -- write ntowrite bytes of generated body text
|
||||
*/
|
||||
|
||||
static int
|
||||
gen_write_body(ptcx, ntowrite, cs)
|
||||
ptcx_t ptcx;
|
||||
int ntowrite;
|
||||
struct checksum_t *cs;
|
||||
{
|
||||
int total = ntowrite;
|
||||
int nwritten;
|
||||
while(ntowrite > 0)
|
||||
{
|
||||
int sz = (ntowrite>gen_bodylen)?gen_bodylen:ntowrite;
|
||||
if((nwritten = GEN_WRITE(gen_body, sz)) < 0)
|
||||
break;
|
||||
ntowrite -= nwritten;
|
||||
if (cs != NULL)
|
||||
cs_data(cs, gen_body, nwritten);
|
||||
}
|
||||
return total - ntowrite;
|
||||
}
|
||||
|
||||
/*
|
||||
** GEN_WRITE_HDRS -- write nhdrs generated headers
|
||||
*/
|
||||
|
||||
static int
|
||||
gen_write_hdrs(ptcx, nhdrs)
|
||||
ptcx_t ptcx;
|
||||
int nhdrs;
|
||||
{
|
||||
int i;
|
||||
int nwritten;
|
||||
int total = 0;
|
||||
/* send extra headers */
|
||||
for(i=0 ; i < nhdrs; i++)
|
||||
{
|
||||
#ifdef __AIX__
|
||||
char buf[128];
|
||||
#else
|
||||
char buf[strlen(GEN_HDRFORMAT) + 5];
|
||||
#endif /* AIX */
|
||||
int len = snprintf(buf, sizeof(buf), GEN_HDRFORMAT, i);
|
||||
|
||||
if((nwritten = GEN_WRITE(buf, len)) < 0)
|
||||
break;
|
||||
total += nwritten;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
** MIME_SEPARATOR -- write a mime separator.
|
||||
*/
|
||||
|
||||
static int
|
||||
mime_separator(ptcx, n, term, cs)
|
||||
ptcx_t ptcx;
|
||||
int n;
|
||||
int term;
|
||||
struct checksum_t *cs;
|
||||
{
|
||||
#ifdef __AIX__
|
||||
char buf[256];
|
||||
#else
|
||||
char buf[strlen(MIME_TERMINATOR) + 8];
|
||||
#endif
|
||||
int len;
|
||||
|
||||
if (term)
|
||||
len = snprintf(buf, sizeof(buf), MIME_TERMINATOR, n);
|
||||
else
|
||||
len = snprintf(buf, sizeof(buf), MIME_SEPARATOR, n);
|
||||
|
||||
DIE_UNLESS(GEN_WRITE(buf, len));
|
||||
if (cs != NULL)
|
||||
cs_data(cs, buf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
** MIME_MULTIPART_HEADERS(ptcx, n, cs) -- write multipart header for depth n
|
||||
**
|
||||
** Note: cs may be NULL if we're in the main rfc822 headers.
|
||||
*/
|
||||
|
||||
static int
|
||||
mime_multipart_headers(ptcx, n, cs)
|
||||
ptcx_t ptcx;
|
||||
int n;
|
||||
struct checksum_t *cs;
|
||||
{
|
||||
#ifdef __AIX__
|
||||
char buf[512];
|
||||
#else
|
||||
char buf[strlen(MIME_MULTIPART_HDR) + 4];
|
||||
#endif
|
||||
int len;
|
||||
len = snprintf(buf, sizeof(buf), MIME_MULTIPART_HDR, n);
|
||||
DIE_UNLESS(GEN_WRITE(buf, len));
|
||||
DIE_UNLESS(GEN_CONSTWRITE(CRLF));
|
||||
if (cs != NULL)
|
||||
{
|
||||
cs_data(cs, buf, len);
|
||||
cs_data(cs, CRLF, strlen(CRLF));
|
||||
}
|
||||
return len + strlen(CRLF);
|
||||
}
|
||||
|
||||
/*
|
||||
** MIME_PART_HEADERS(ptcx, type, name) -- write part headers.
|
||||
*/
|
||||
|
||||
static int
|
||||
mime_part_headers(ptcx, type, name, cs)
|
||||
ptcx_t ptcx;
|
||||
char *type;
|
||||
char *name;
|
||||
struct checksum_t *cs;
|
||||
{
|
||||
#ifdef __AIX__
|
||||
char buf[512];
|
||||
#else
|
||||
char buf[strlen(MIME_PART_HDR) + 128];
|
||||
#endif
|
||||
int len;
|
||||
len = snprintf(buf, sizeof(buf), MIME_PART_HDR, type, name);
|
||||
DIE_UNLESS(GEN_WRITE(buf, len));
|
||||
DIE_UNLESS(GEN_CONSTWRITE(CRLF));
|
||||
|
||||
if (cs != NULL)
|
||||
{
|
||||
cs_data(cs, buf, len);
|
||||
cs_data(cs, CRLF, strlen(CRLF));
|
||||
}
|
||||
return len + strlen(CRLF);
|
||||
}
|
||||
|
||||
/*
|
||||
** GENERATE_MESSAGE -- generate a message according to pish
|
||||
*/
|
||||
|
||||
int
|
||||
generateMessage(ptcx_t ptcx, pish_command_t *pish)
|
||||
{
|
||||
static int mime_multi_overhead = -1,
|
||||
mime_single_overhead = -1;
|
||||
int nwritten;
|
||||
int msgsize;
|
||||
int nhdrs;
|
||||
int mime;
|
||||
int ntowrite;
|
||||
int i;
|
||||
struct checksum_t *cs = NULL;
|
||||
char *cs_rep = NULL;
|
||||
|
||||
assert(ptcx != NULL);
|
||||
assert(pish != NULL);
|
||||
|
||||
/* Calculate message size: */
|
||||
msgsize = sample(pish->genSize);
|
||||
|
||||
/* calculate other message parameters: */
|
||||
nhdrs = sample(pish->genHdrs);
|
||||
mime = sample(pish->genMime);
|
||||
|
||||
ntowrite = msgsize;
|
||||
|
||||
assert(msgsize >= 0);
|
||||
/* send default headers */
|
||||
#ifdef GEN_MSGIDS
|
||||
{
|
||||
/* XXX: not threadsafe, but shouldn't matter */
|
||||
static long msgnum = 0;
|
||||
int n;
|
||||
# ifdef __AIX__
|
||||
/*
|
||||
** Stop for a moment to loathe xlc_r, which cannot
|
||||
** figure out static string lengths at compile time.
|
||||
*/
|
||||
char buf[512];
|
||||
# else /* __AIX__ */
|
||||
char buf[strlen(GEN_HDRS)+128];
|
||||
# endif /* __AIX__ */
|
||||
struct tm now;
|
||||
time_t tnow;
|
||||
char timebuf[64];
|
||||
tnow = time(0);
|
||||
(void) gmtime_r(&tnow, &now);
|
||||
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %T -0000",
|
||||
&now);
|
||||
n = snprintf(buf, sizeof(buf), GEN_HDRS,
|
||||
ptcx->processnum,
|
||||
ptcx->threadnum,
|
||||
msgnum++,
|
||||
timebuf);
|
||||
DIE_UNLESS(nwritten = GEN_WRITE(buf, n));
|
||||
}
|
||||
#else /* GEN_MSGIDS */
|
||||
DIE_UNLESS(nwritten = GEN_CONSTWRITE(GEN_HDRS));
|
||||
#endif /* GEN_MSGIDS */
|
||||
|
||||
#ifdef GEN_HDR_SIZE_COUNTS
|
||||
ntowrite -= nwritten;
|
||||
#endif /* GEN_HDR_SIZE_COUNTS */
|
||||
|
||||
nhdrs -= N_GEN_HDRS;
|
||||
|
||||
/* send additional headers, if necessary */
|
||||
if(nhdrs > 0)
|
||||
{
|
||||
DIE_UNLESS(nwritten = gen_write_hdrs(ptcx, nhdrs));
|
||||
#ifdef GEN_HDR_SIZE_COUNTS
|
||||
ntowrite -= nwritten;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* figure out how many mime parts we can create */
|
||||
/* (our message might be too small to have any mime parts) */
|
||||
if (mime > 0)
|
||||
{
|
||||
/* approximate overhead */
|
||||
if (mime_multi_overhead < 0)
|
||||
{
|
||||
mime_multi_overhead = strlen(MIME_SEPARATOR)
|
||||
+ strlen(MIME_MULTIPART_HDR)
|
||||
+ strlen(MIME_WARNING)
|
||||
+ strlen(MIME_TERMINATOR);
|
||||
|
||||
mime_single_overhead = strlen(MIME_SEPARATOR)
|
||||
+ strlen(MIME_PART_HDR);
|
||||
}
|
||||
|
||||
if ((ntowrite - mime_multi_overhead * mime
|
||||
< mime_single_overhead))
|
||||
{
|
||||
mime = (ntowrite - mime_single_overhead)
|
||||
/ mime_multi_overhead;
|
||||
assert(mime >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Checksums are taken over the body, from after the blank
|
||||
** line following the headers to just before the CRLF.CRLF.
|
||||
*/
|
||||
|
||||
if (mime > 0)
|
||||
{
|
||||
int bodylen = ntowrite
|
||||
- (mime - 1) * mime_multi_overhead
|
||||
- mime_single_overhead
|
||||
- strlen(MIME_TERMINATOR);
|
||||
|
||||
for (i = 0; i < mime - 1; i++)
|
||||
{
|
||||
/* write multipart header for i */
|
||||
DIE_UNLESS(nwritten = \
|
||||
mime_multipart_headers(ptcx, i, cs));
|
||||
ntowrite -= nwritten;
|
||||
|
||||
#ifdef GEN_CHECKSUM
|
||||
if (i == 0
|
||||
&& pish->genChecksum != CS_NONE
|
||||
&& (cs = cs_begin(CS_MD5)) == NULL)
|
||||
fprintf(stderr, "generateMessage: can't initialize checksum\n");
|
||||
#endif /* GEN_CHECKSUM */
|
||||
DIE_UNLESS(nwritten = GEN_CONSTWRITE(MIME_WARNING));
|
||||
ntowrite -= nwritten;
|
||||
if (cs != NULL)
|
||||
cs_data(cs, MIME_WARNING,
|
||||
strlen(MIME_WARNING));
|
||||
|
||||
/* write boundary for i */
|
||||
DIE_UNLESS(nwritten = \
|
||||
mime_separator(ptcx, i, 0, cs));
|
||||
ntowrite -= nwritten;
|
||||
}
|
||||
|
||||
/* write single-part body */
|
||||
|
||||
if (mime > 1)
|
||||
DIE_UNLESS(nwritten = \
|
||||
mime_part_headers(ptcx, \
|
||||
MIME_TYPE, \
|
||||
MIME_FILE, cs));
|
||||
else
|
||||
DIE_UNLESS(nwritten = \
|
||||
mime_part_headers(ptcx, \
|
||||
MIME_TYPE, \
|
||||
MIME_FILE, NULL));
|
||||
|
||||
ntowrite -= nwritten;
|
||||
|
||||
DIE_UNLESS(nwritten = \
|
||||
gen_write_body(ptcx, bodylen, cs));
|
||||
ntowrite -= nwritten;
|
||||
|
||||
/* write mime terminators for all sections */
|
||||
for (i = mime - 1; i >= 0; i--)
|
||||
{
|
||||
DIE_UNLESS(nwritten = mime_separator(ptcx, i, 1, cs));
|
||||
ntowrite -= nwritten;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write end of headers */
|
||||
DIE_UNLESS(nwritten = GEN_CONSTWRITE(CRLF));
|
||||
#ifdef GEN_HDR_SIZE_COUNTS
|
||||
ntowrite -= nwritten;
|
||||
#endif
|
||||
#ifdef GEN_CHECKSUM
|
||||
if (pish->genChecksum != CS_NONE
|
||||
&& (cs = cs_begin(CS_MD5)) == NULL)
|
||||
fprintf(stderr,
|
||||
"generateMessage: can't initialize checksum\n");
|
||||
#endif /* GEN_CHECKSUM */
|
||||
/* send non-MIME body */
|
||||
if(ntowrite > 0)
|
||||
{
|
||||
DIE_UNLESS(nwritten = \
|
||||
gen_write_body(ptcx, ntowrite, cs));
|
||||
ntowrite -= nwritten;
|
||||
}
|
||||
}
|
||||
/* done sending body. Checksum then EOM. */
|
||||
if (cs != NULL)
|
||||
{
|
||||
/* add in crlf at start of CS_MARKER */
|
||||
cs_data(cs, CRLF, strlen(CRLF));
|
||||
cs_rep = cs_end(cs);
|
||||
DIE_UNLESS(GEN_WRITE(cs_rep, strlen(cs_rep)));
|
||||
xfree(cs_rep);
|
||||
xfree(cs);
|
||||
}
|
||||
|
||||
DIE_UNLESS(GEN_CONSTWRITE(EOM));
|
||||
ntowrite -= strlen(EOM);
|
||||
/* update stats */
|
||||
if(ntowrite > 0)
|
||||
fprintf(stderr,
|
||||
"generateMessage: notice: generated %d/%d bytes\n",
|
||||
msgsize-ntowrite, msgsize);
|
||||
msgsize -= ntowrite;
|
||||
|
||||
if(msgsize <= 0)
|
||||
fprintf(stderr,
|
||||
"generateMessage: notice: msgsize = %d\n", msgsize);
|
||||
|
||||
ptcx->byteswritten += msgsize;
|
||||
return msgsize;
|
||||
}
|
||||
|
||||
#endif /* AUTOGEN */
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _generate_h
|
||||
#define _generate_h
|
||||
|
||||
#ifdef AUTOGEN
|
||||
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
|
||||
int generateMessage (ptcx_t , pish_command_t*);
|
||||
void gen_init();
|
||||
|
||||
#endif /* AUTOGEN */
|
||||
|
||||
#endif /* _generate_h */
|
||||
@@ -20,7 +20,6 @@
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -132,7 +131,6 @@ HttpReadResponse(
|
||||
|
||||
D_PRINTF(stderr, "HttpReadResponse()\n");
|
||||
|
||||
/* Sean O'Rourke: this is not correct */
|
||||
findStr = HTTP_CONTENT_LENGTH;
|
||||
searchStart = buffer;
|
||||
memset(buffer, 0, buflen); /* DEBUG */
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -37,7 +36,6 @@
|
||||
|
||||
#include "bench.h"
|
||||
#include "http-util.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#define MAX_HTTP_RESPONSE_LEN (2*1024) /* size of sliding buffer */
|
||||
|
||||
@@ -86,7 +84,8 @@ HttpParseStart (pmail_command_t cmd,
|
||||
param_list_t *defparm)
|
||||
{
|
||||
param_list_t *pp;
|
||||
http_command_t *mycmd = XCALLOC(struct http_command);
|
||||
http_command_t *mycmd = (http_command_t *)mycalloc
|
||||
(sizeof (http_command_t));
|
||||
cmd->data = mycmd;
|
||||
|
||||
cmd->numLoops = 1; /* default 1 downloads */
|
||||
@@ -172,11 +171,11 @@ HttpParseNameValue (pmail_command_t cmd,
|
||||
if (cmdParseNameValue(cmd, name, tok))
|
||||
; /* done */
|
||||
else if (strcmp(name, "server") == 0)
|
||||
mycmd->hostInfo.hostName = xstrdup (tok);
|
||||
mycmd->hostInfo.hostName = mystrdup (tok);
|
||||
else if (strcmp(name, "portnum") == 0)
|
||||
mycmd->hostInfo.portNum = atoi(tok);
|
||||
else if (strcmp(name, "httpcommand") == 0)
|
||||
mycmd->httpCommand = xstrdup (tok);
|
||||
mycmd->httpCommand = mystrdup (tok);
|
||||
/*stringListAdd(&mycmd->getFirstCmds, tok);*/
|
||||
else {
|
||||
return -1;
|
||||
@@ -191,7 +190,7 @@ HttpStatsInit(mail_command_t *cmd, cmd_stats_t *p, int procNum, int threadNum)
|
||||
assert (NULL != p);
|
||||
|
||||
if (!p->data) { /* create it */
|
||||
p->data = XCALLOC(struct http_stats);
|
||||
p->data = mycalloc (sizeof (http_stats_t));
|
||||
} else { /* zero it */
|
||||
memset (p->data, 0, sizeof (http_stats_t));
|
||||
}
|
||||
@@ -301,7 +300,7 @@ HttpStatsFormat (protocol_t *pp,
|
||||
void *
|
||||
doHttpStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
{
|
||||
doHTTP_state_t *me = XCALLOC(doHTTP_state_t);
|
||||
doHTTP_state_t *me = (doHTTP_state_t *)mycalloc (sizeof (doHTTP_state_t));
|
||||
http_stats_t *stats = (http_stats_t *)ptimer->data;
|
||||
http_command_t *mycmd = (http_command_t *)cmd->data;
|
||||
|
||||
@@ -402,5 +401,5 @@ doHttpExit (ptcx_t ptcx, doHTTP_state_t *me)
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
|
||||
xfree (me);
|
||||
myfree (me);
|
||||
}
|
||||
|
||||
@@ -1,403 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#define __USE_ISOC9X 1 /* for NAN on Linux */
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef NAN
|
||||
# define NOLIMIT NAN
|
||||
#elif defined(DBL_MAX)
|
||||
# define NOLIMIT DBL_MAX
|
||||
#elif defined(FLT_MAX)
|
||||
# define NOLIMIT FLT_MAX
|
||||
#elif defined(MAXFLOAT)
|
||||
# define NOLIMIT MAXFLOAT
|
||||
#else
|
||||
/* this is what FLT_MAX looks like on linux 2.2.x */
|
||||
# define NOLIMIT ((float)3.40282346638528860e+38)
|
||||
#endif
|
||||
|
||||
#include "idle.h"
|
||||
#ifndef TEST_PROB
|
||||
#include "bench.h"
|
||||
#endif
|
||||
#include "xalloc.h"
|
||||
|
||||
/* UNIF01 -- a random variable with a distribution ~Unif(0,1). */
|
||||
#define UNIF01 (drand48())
|
||||
/* STDNORMAL -- a random variable with distribution ~N(0,1) */
|
||||
#define STDNORMAL (sqrt(-2*log(UNIF01))*cos(2*M_PI*UNIF01))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
distrib_func_t func;
|
||||
int nparams;
|
||||
} distribution_t;
|
||||
|
||||
/*
|
||||
** CONST(X) -- constant value of X
|
||||
*/
|
||||
static double
|
||||
_constant(params)
|
||||
double *params;
|
||||
{
|
||||
return params[0];
|
||||
}
|
||||
|
||||
static distribution_t constant = { "const", &_constant, 1 };
|
||||
|
||||
dinst_t *
|
||||
constant_value(val)
|
||||
double val;
|
||||
{
|
||||
dinst_t *ret = xalloc(sizeof(dinst_t));
|
||||
|
||||
ret->min = ret->max = NOLIMIT;
|
||||
ret->func = &_constant;
|
||||
ret->params[0] = val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** UNIF(a, b) -- distribution ~unif(a, b)
|
||||
*/
|
||||
static double
|
||||
_uniform(params)
|
||||
double *params;
|
||||
{
|
||||
return params[0] + UNIF01*(params[1] - params[0]);
|
||||
}
|
||||
|
||||
static distribution_t uniform = { "unif", &_uniform, 2 };
|
||||
|
||||
/*
|
||||
** EXP(mu) -- idle times distributed as ~exp(1/mu).
|
||||
*/
|
||||
static double
|
||||
_exponential(params)
|
||||
double * params;
|
||||
{
|
||||
return -params[0]*log(UNIF01);
|
||||
}
|
||||
|
||||
static distribution_t exponential = { "exp", &_exponential, 1 };
|
||||
|
||||
/*
|
||||
** WEIB(mu, alpha, gamma) -- Weibull distribution.
|
||||
**
|
||||
** The Weibull function f(x) = g/a * ((x-m)/a)^(g-1) * e^(-(x-m)/a)^g
|
||||
**
|
||||
** gamma <= 1.0
|
||||
*/
|
||||
|
||||
static double
|
||||
_weibull(params)
|
||||
double * params;
|
||||
{
|
||||
return params[0] - params[1]*pow(log(1.0 - UNIF01), 1.0/params[2]);
|
||||
}
|
||||
|
||||
static distribution_t weibull = { "weib", &_weibull, 3 };
|
||||
|
||||
/*
|
||||
** NORMAL(mu, sigma) -- ~normal(mu, sigma).
|
||||
*/
|
||||
static double
|
||||
_normal(params)
|
||||
double * params;
|
||||
{
|
||||
return params[0] + params[1]*STDNORMAL;
|
||||
}
|
||||
|
||||
static distribution_t normal = { "normal", &_normal, 2 };
|
||||
|
||||
/*
|
||||
** LOGNORMAL(a, b) -- ~lognormal(a, b).
|
||||
*/
|
||||
static double
|
||||
_lognormal(params)
|
||||
double * params;
|
||||
{
|
||||
return params[0]*exp(sqrt(params[1])*STDNORMAL);
|
||||
}
|
||||
|
||||
static distribution_t lognormal = { "lognormal", &_lognormal, 2 };
|
||||
|
||||
#if 0 /* not ready for prime-time */
|
||||
/*
|
||||
** POISSON(mu) -- ~poisson(mu)
|
||||
*/
|
||||
static double
|
||||
_poisson(params)
|
||||
double * params;
|
||||
{
|
||||
}
|
||||
|
||||
static distribution_t poisson = { "poisson", &_poisson, 1 };
|
||||
#endif
|
||||
|
||||
/*
|
||||
** BINOMIAL(mu) -- ~binomial(p)
|
||||
*/
|
||||
static double
|
||||
_binomial(params)
|
||||
double * params;
|
||||
{
|
||||
return UNIF01 < params[0];
|
||||
}
|
||||
|
||||
static distribution_t binomial = { "binomial", &_binomial, 1 };
|
||||
|
||||
dinst_t *
|
||||
percentage(val)
|
||||
double val;
|
||||
{
|
||||
dinst_t *ret = xalloc(sizeof(dinst_t));
|
||||
ret->min = ret->max = NOLIMIT;
|
||||
assert(val >= 0 && val <= 1.0);
|
||||
ret->func = &_binomial;
|
||||
ret->params[0] = val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static distribution_t *distributions[] =
|
||||
{
|
||||
&constant,
|
||||
&uniform,
|
||||
&exponential,
|
||||
&weibull,
|
||||
&normal,
|
||||
&lognormal,
|
||||
&binomial,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int
|
||||
parse_params(tok, n, params, value_parser)
|
||||
char *tok;
|
||||
int n;
|
||||
double *params;
|
||||
value_parser_t value_parser;
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
for(p = strtok(tok, ","), i = 0;
|
||||
p != NULL && i < n;
|
||||
p = strtok(NULL, ","), i++)
|
||||
{
|
||||
params[i] = (*value_parser)(p);
|
||||
if(params[i] == 0 && *p != '0')
|
||||
fprintf(stderr,
|
||||
"Warning: parameter '%s' parsed to 0 -- syntax error?\n", p);
|
||||
}
|
||||
if(i < n || p != NULL)
|
||||
{
|
||||
fprintf(stderr, "Parse error: %s.\n",
|
||||
(i < n)?"not enough parameters":"too many parameters");
|
||||
return -1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
strsub(dest, begin, end)
|
||||
char *dest, *begin, *end;
|
||||
{
|
||||
while(begin < end && *begin)
|
||||
*dest++ = *begin++;
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
dinst_t *
|
||||
parse_distrib(tok, value_parser)
|
||||
char *tok;
|
||||
value_parser_t value_parser;
|
||||
{
|
||||
char name[20], params[80];
|
||||
distribution_t** d;
|
||||
char *oparen, *cparen;
|
||||
char *p = tok;
|
||||
double cmin, cmax;
|
||||
|
||||
if ((tok = strchr(tok, '~')) == NULL)
|
||||
{
|
||||
double val = value_parser(p);
|
||||
if(strchr(p, '%'))
|
||||
return percentage(val/100.0);
|
||||
return constant_value(val);
|
||||
}
|
||||
++tok; /* skip over tilde */
|
||||
oparen = strchr(tok, '(');
|
||||
if (oparen == NULL)
|
||||
{
|
||||
assert(!"no open parenthesis");
|
||||
return NULL;
|
||||
}
|
||||
strsub(name, tok, oparen);
|
||||
if ((cparen = strchr(oparen, ')')) == NULL)
|
||||
{
|
||||
assert(!"no closing parenthesis");
|
||||
return NULL;
|
||||
}
|
||||
strsub(params, oparen+1, cparen);
|
||||
|
||||
/* now look for constraints == ':' '[' [min] ',' [max] ']' */
|
||||
cmin = cmax = NOLIMIT;
|
||||
if ((cparen = strchr(cparen, ':')) != NULL
|
||||
&& (oparen = strchr(cparen, '[')) != NULL
|
||||
&& (p = strchr(oparen + 1, ',')) != NULL
|
||||
&& (cparen = strchr(p + 1, ']')) != NULL)
|
||||
{
|
||||
*p = '\0';
|
||||
*cparen = '\0';
|
||||
/* skip whitespace */
|
||||
while (isspace(*++oparen))
|
||||
;
|
||||
if (oparen < p)
|
||||
cmin = (*value_parser)(oparen);
|
||||
|
||||
while (isspace(*++p))
|
||||
;
|
||||
if (p < cparen)
|
||||
cmax = (*value_parser)(p);
|
||||
}
|
||||
|
||||
for (d = distributions; *d; d++)
|
||||
{
|
||||
if(strcmp(name, (*d)->name) == 0)
|
||||
{
|
||||
dinst_t *ret = xalloc(sizeof(dinst_t)
|
||||
+ ((*d)->nparams - 1)*sizeof(double));
|
||||
|
||||
if(parse_params(params, (*d)->nparams, &ret->params,
|
||||
value_parser)
|
||||
< 0)
|
||||
{
|
||||
xfree(ret);
|
||||
assert(!"parse_params failed");
|
||||
return NULL;
|
||||
}
|
||||
ret->func = (*d)->func;
|
||||
ret->min = cmin;
|
||||
ret->max = cmax;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "No such distribution: '%s'\n", name);
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double
|
||||
sample(inst)
|
||||
dinst_t *inst;
|
||||
{
|
||||
double ret;
|
||||
if(inst == NULL)
|
||||
return 0;
|
||||
ret = (inst->func)(inst->params);
|
||||
|
||||
/* constrain value */
|
||||
if ((inst->min != NOLIMIT) && ret < inst->min)
|
||||
ret = inst->min;
|
||||
if ((inst->max != NOLIMIT) && ret > inst->max)
|
||||
ret = inst->max;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROB
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
char buf[80];
|
||||
dinst_t *distrib;
|
||||
extern char *optarg;
|
||||
char c;
|
||||
int nsamples = 2000;
|
||||
while((c = getopt(argc, argv, "n:")) != EOF)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case 'n':
|
||||
nsamples = atoi(optarg);
|
||||
break;
|
||||
case '?':
|
||||
printf("Unrecognized option '%c'\n", c);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(1)
|
||||
{
|
||||
double var, mean;
|
||||
gets(buf);
|
||||
if(feof(stdin))
|
||||
exit(0);
|
||||
if((distrib = parse_distrib(buf, &atof)))
|
||||
{
|
||||
int i;
|
||||
double total = 0;
|
||||
double sq = 0;
|
||||
fprintf(stderr, "Samples:\n");
|
||||
for(i=0; i<10; ++i)
|
||||
{
|
||||
double samp = sample(distrib);
|
||||
total += samp;
|
||||
sq += samp * samp;
|
||||
fprintf(stderr, "%f\n", samp);
|
||||
}
|
||||
for( ; i<nsamples; ++i)
|
||||
{
|
||||
double samp = sample(distrib);
|
||||
total += samp;
|
||||
sq += samp * samp;
|
||||
}
|
||||
mean = total / (double)nsamples;
|
||||
var = (sq / (double)nsamples - mean * mean);
|
||||
fprintf(stderr, "mean: %f\nvar: %f\nstddev: %f\n",
|
||||
mean, var, sqrt(var));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* TEST_PROB */
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _idle_h
|
||||
#define _idle_h
|
||||
|
||||
typedef double (*distrib_func_t)(double*);
|
||||
typedef double (*value_parser_t)(char*);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
distrib_func_t func;
|
||||
double min, max;
|
||||
double params[1]; /* actual length varies by distribution */
|
||||
} dinst_t;
|
||||
|
||||
extern dinst_t *parse_distrib(char*, value_parser_t);
|
||||
extern dinst_t *constant_value(double);
|
||||
extern double sample(dinst_t *);
|
||||
|
||||
#endif /* _idle_h */
|
||||
@@ -21,8 +21,6 @@
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -39,10 +37,6 @@
|
||||
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
#include "idle.h"
|
||||
#include "socket.h"
|
||||
#include "xalloc.h"
|
||||
#include "checksum.h"
|
||||
|
||||
typedef struct IMAP_t {
|
||||
int seq_num; /* IMAP command seq number */
|
||||
@@ -51,11 +45,7 @@ typedef struct IMAP_t {
|
||||
} IMAP;
|
||||
|
||||
/* protos */
|
||||
#if 0
|
||||
static int retrImapMsg(ptcx_t ptcx, SOCKET sock, int seqNum, char *buffer, int msgSize, int maxBytes);
|
||||
#else
|
||||
static int retrImapMsg(ptcx_t ptcx, SOCKET sock, int seqNum, int msgSize);
|
||||
#endif /* 0 */
|
||||
static int readImapResponse(ptcx_t ptcx, SOCKET sock, int seqNum, char *buffer, int buflen);
|
||||
static int doImapCommandResponse(ptcx_t ptcx, SOCKET sock, int SeqNum, char *cmdand, char *response, int resplen);
|
||||
|
||||
@@ -82,7 +72,7 @@ typedef struct _doIMAP4_state {
|
||||
int *searchSchedule;
|
||||
} doIMAP4_state_t;
|
||||
|
||||
/* flags definitions */
|
||||
/* IMAP flags definitions */
|
||||
#define leaveMailOnServer 0x01
|
||||
#define leaveMailUnseen 0x02
|
||||
|
||||
@@ -98,29 +88,27 @@ ImapParseNameValue (pmail_command_t cmd,
|
||||
|
||||
/* find a home for the attr/value */
|
||||
if (pishParseNameValue(cmd, name, tok) == 0)
|
||||
; /* done */
|
||||
; /* done */
|
||||
else if (strcmp(name, "leavemailonserver") == 0) {
|
||||
if (atoi(tok) > 0) {
|
||||
pish->flags |= leaveMailOnServer;
|
||||
pish->leaveMailOnServerDist =
|
||||
parse_distrib(tok, (value_parser_t)&atof);
|
||||
} else { /* turn on if < leavemailunseen */
|
||||
pish->flags &= ~leaveMailOnServer;
|
||||
/* D_PRINTF (stderr, "leaveMailOnServer=%d\n", pish->leaveMailOnServer);*/
|
||||
}
|
||||
}
|
||||
pish->flags |= leaveMailOnServer;
|
||||
} else { /* turn on if < leavemailunseen */
|
||||
pish->flags &= ~leaveMailOnServer;
|
||||
}
|
||||
/*D_PRINTF (stderr, "leaveMailOnServer=%d\n", pish->leaveMailOnServer);*/
|
||||
}
|
||||
else if (strcmp(name, "leavemailunseen") == 0) {
|
||||
if (atoi(tok) > 0) {
|
||||
/* leaving mail unseen implies leaving on server */
|
||||
pish->flags |= leaveMailUnseen | leaveMailOnServer;
|
||||
} else { /* turn on if < leavemailunseen */
|
||||
pish->flags &= ~leaveMailUnseen;
|
||||
}
|
||||
/*D_PRINTF (stderr, "leaveMailOnServer=%d\n", pish->leaveMailOnServer);*/
|
||||
if (atoi(tok) > 0) {
|
||||
/* leaving mail unseen implies leaving on server */
|
||||
pish->flags |= leaveMailUnseen | leaveMailOnServer;
|
||||
} else { /* turn on if < leavemailunseen */
|
||||
pish->flags &= ~leaveMailUnseen;
|
||||
}
|
||||
/*D_PRINTF (stderr, "leaveMailOnServer=%d\n", pish->leaveMailOnServer);*/
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -133,10 +121,11 @@ Imap4ParseStart (pmail_command_t cmd,
|
||||
param_list_t *defparm)
|
||||
{
|
||||
param_list_t *pp;
|
||||
pish_command_t *pish = XCALLOC(pish_command_t);
|
||||
|
||||
pish_command_t *pish = (pish_command_t *)mycalloc
|
||||
(sizeof (pish_command_t));
|
||||
cmd->data = pish;
|
||||
|
||||
cmd->loopDelay = 10*60; /* default 10 min */
|
||||
pish->hostInfo.portNum = IMAP4_PORT; /* get default port */
|
||||
|
||||
D_PRINTF(stderr, "Imap4 Assign defaults\n");
|
||||
@@ -173,10 +162,8 @@ Imap4ParseEnd (pmail_command_t cmd,
|
||||
|
||||
if (ImapParseNameValue (cmd, name, tok) < 0) {
|
||||
/* not a known attr */
|
||||
D_PRINTF(stderr,"notice: ignoring unknown attribute '%s' '%s'\n",
|
||||
name, tok);
|
||||
returnerr(stderr,"notice: ignoring unknown attribute '%s' '%s'\n",
|
||||
name, tok);
|
||||
D_PRINTF(stderr,"unknown attribute '%s' '%s'\n", name, tok);
|
||||
returnerr(stderr,"unknown attribute '%s' '%s'\n", name, tok);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,11 +209,11 @@ Imap4ParseEnd (pmail_command_t cmd,
|
||||
void *
|
||||
doImap4Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
{
|
||||
doIMAP4_state_t *me = XCALLOC(doIMAP4_state_t);
|
||||
doIMAP4_state_t *me = (doIMAP4_state_t *)mycalloc (sizeof (doIMAP4_state_t));
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
int rc;
|
||||
|
||||
|
||||
if (!me) return NULL;
|
||||
me->pIMAP = &me->IMAP_state;
|
||||
|
||||
@@ -237,8 +224,6 @@ doImap4Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
|
||||
me->pIMAP->seq_num = 1;
|
||||
|
||||
ptcx->net_timeout = pish->net_timeout;
|
||||
|
||||
event_start(ptcx, &stats->connect);
|
||||
ptcx->sock = connectSocket(ptcx, &pish->hostInfo, "tcp");
|
||||
event_stop(ptcx, &stats->connect);
|
||||
@@ -248,37 +233,16 @@ doImap4Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
returnerr(debugfile, "IMAP4 Couldn't connect to %s: %s\n",
|
||||
pish->hostInfo.hostName, neterrstr());
|
||||
}
|
||||
xfree (me);
|
||||
myfree (me);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (gf_abortive_close) {
|
||||
if (set_abortive_close(ptcx->sock) != 0) {
|
||||
returnerr (debugfile, "IMAP: WARNING: Could not set abortive close\n");
|
||||
returnerr (debugfile, "SMTP: WARNING: Could not set abortive close\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Sean O'Rourke: add socket "flavors" */
|
||||
#ifdef SOCK_SSL
|
||||
if (pish->sslTunnel) {
|
||||
SSL_INIT(ptcx->sock, pish);
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
returnerr(debugfile, "IMAP ERROR: Could not start SSL tunneling\n");
|
||||
stats->connect.errs++;
|
||||
xfree (me);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
LS_INIT(ptcx->sock, pish);
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
returnerr(debugfile, "IMAP ERROR: can't initialize socket.\n");
|
||||
stats->connect.errs++; /* (sort of) */
|
||||
xfree (me);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* READ connect response from server */
|
||||
event_start(ptcx, &stats->banner);
|
||||
rc = readResponse(ptcx, ptcx->sock, me->pIMAP->resp_buffer, sizeof(me->pIMAP->resp_buffer));
|
||||
@@ -293,49 +257,6 @@ doImap4Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
if (!pish->useTLS)
|
||||
goto end_tls;
|
||||
|
||||
/*
|
||||
** Try to do STARTTLS
|
||||
*/
|
||||
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doImapCommandResponse(ptcx, ptcx->sock, ++me->pIMAP->seq_num,
|
||||
"CAPABILITY" CRLF,
|
||||
me->pIMAP->resp_buffer,
|
||||
sizeof(me->pIMAP->resp_buffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
stats->cmd.errs++;
|
||||
goto end_tls;
|
||||
}
|
||||
if (strstr(me->pIMAP->resp_buffer, "STARTTLS")) {
|
||||
SOCKET s = BADSOCKET_VALUE;
|
||||
D_PRINTF(debugfile, "Trying STARTTLS\n");
|
||||
if (doImapCommandResponse(ptcx, ptcx->sock, ++me->pIMAP->seq_num,
|
||||
"STARTTLS" CRLF,
|
||||
me->pIMAP->resp_buffer,
|
||||
sizeof(me->pIMAP->resp_buffer)) >= 0) {
|
||||
char *p = me->pIMAP->resp_buffer;
|
||||
while (*p && !isspace(*p++))
|
||||
;
|
||||
if (strncmp(p, "OK", 2) == 0) {
|
||||
s = ptcx->sock;
|
||||
SSL_INIT(s, pish);
|
||||
}
|
||||
}
|
||||
if (BADSOCKET(s)) {
|
||||
D_PRINTF(stderr, "Can't use TLS\n");
|
||||
} else {
|
||||
ptcx->sock = s;
|
||||
}
|
||||
}
|
||||
end_tls:
|
||||
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
rc = imapLogin(ptcx, me->pIMAP, ptcx->sock, cmd, ptimer);
|
||||
if (rc != 0) {
|
||||
doImap4Exit (ptcx, me);
|
||||
@@ -349,6 +270,7 @@ doImap4Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
me->currentSearch = me->numSearches = 0;
|
||||
if (pish->imapSearchRate) {
|
||||
me->numSearches = imapComputeSearchSchedule(ptcx, cmd, &me->searchSchedule);
|
||||
(void)me->numSearches; /* ??? */
|
||||
me->timeUntilSearch = me->searchSchedule[me->currentSearch];
|
||||
}
|
||||
|
||||
@@ -375,8 +297,15 @@ doImap4Loop(ptcx_t ptcx,
|
||||
return -1; /* signal to logout, clean up */
|
||||
}
|
||||
|
||||
#if 0 /* update for new loop model */
|
||||
rc = selectFolder(ptcx, me->pIMAP, ptcx->sock, "INBOX", ptimer); /* does NOOP */
|
||||
if (rc != 0) {
|
||||
return -1; /* signal to clean up */
|
||||
}
|
||||
#endif
|
||||
|
||||
if (me->searchSchedule) { /* check if it's time to search */
|
||||
me->timeUntilSearch -= sample(cmd->loopDelay);
|
||||
me->timeUntilSearch -= cmd->loopDelay;
|
||||
|
||||
if (me->timeUntilSearch <= 0) {
|
||||
imapSearchFolder(ptcx, me->pIMAP, ptcx->sock, cmd, ptimer);
|
||||
@@ -398,36 +327,6 @@ doImap4End(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
||||
if (!me) return;
|
||||
if (BADSOCKET(ptcx->sock)) return; /* closed by previous error */
|
||||
|
||||
/* Sean O'Rourke: add ramp-down time: */
|
||||
|
||||
#ifdef IMAP_RAMPDOWN
|
||||
while(gf_timeexpired >= EXIT_SOON) {
|
||||
int mystoptime = gt_shutdowntime
|
||||
+ ptcx->threadnum*gt_stopinterval*EXIT_FAST / gn_numthreads;
|
||||
int secsleft = mystoptime - time(0L);
|
||||
if(secsleft > 0)
|
||||
{
|
||||
#ifdef PROB_RAMPDOWN
|
||||
extern value_parser_t d_millitime_atoi;
|
||||
char dist[64];
|
||||
int sleepms;
|
||||
dinst_t* unif;
|
||||
sprintf(dist, "~unif(0, %ds)", secsleft);
|
||||
unif = parse_distrib(dist, d_millitime_atoi);
|
||||
sleepms = sample(unif);
|
||||
MS_usleep(1000*sleepms);
|
||||
#else /* PROB_RAMPDOWN */
|
||||
/* First threads started are first to terminate: */
|
||||
MS_sleep((int)(secsleft));
|
||||
#endif /* PROB_RAMPDOWN */
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* IMAP_RAMPDOWN */
|
||||
|
||||
/* close the folder */
|
||||
rc = imapCloseFolder(ptcx, me->pIMAP, ptcx->sock, ptimer);
|
||||
if (rc != 0) {
|
||||
@@ -464,9 +363,9 @@ doImap4Exit (ptcx_t ptcx, doIMAP4_state_t *me)
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
|
||||
if (me->searchSchedule)
|
||||
xfree(me->searchSchedule);
|
||||
myfree(me->searchSchedule);
|
||||
|
||||
xfree (me);
|
||||
myfree (me);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -516,24 +415,19 @@ readImapResponse(ptcx_t ptcx, SOCKET sock, int seqNum, char *buffer, int buflen)
|
||||
|
||||
/* read from socket until we find <CRLF>.<CRLF> */
|
||||
static int
|
||||
#if 0
|
||||
retrImapMsg(ptcx_t ptcx, SOCKET sock, int seqNum,
|
||||
char *buffer, int msgSize, int maxBytes)
|
||||
#else
|
||||
retrImapMsg(ptcx_t ptcx, SOCKET sock, int seqNum, int msgSize)
|
||||
#endif
|
||||
{
|
||||
int totalbytesread = 0;
|
||||
int bytesread;
|
||||
int maxBytes = msgSize + 1024; /* old semantics */
|
||||
char markerSingleLine[20];
|
||||
char markerMultiLine[20];
|
||||
char buf[4096];
|
||||
char *bpos = buf;
|
||||
|
||||
/* marker to tell us when we've recieved the final line from server */
|
||||
sprintf(markerSingleLine, "%d ", seqNum);
|
||||
sprintf(markerMultiLine, "\n%d ", seqNum);
|
||||
|
||||
memset (buffer, 0, maxBytes);
|
||||
|
||||
while (totalbytesread < maxBytes)
|
||||
{
|
||||
@@ -542,10 +436,7 @@ retrImapMsg(ptcx_t ptcx, SOCKET sock, int seqNum, int msgSize)
|
||||
break;
|
||||
}
|
||||
|
||||
bytesread = maxBytes - totalbytesread;
|
||||
if (bytesread > sizeof(buf) - (1 + bpos - buf))
|
||||
bytesread = sizeof(buf) - (1 + bpos - buf);
|
||||
bytesread = retryRead(ptcx, sock, bpos, bytesread);
|
||||
bytesread = retryRead(ptcx, sock, buffer+totalbytesread, maxBytes-totalbytesread);
|
||||
if (bytesread <= 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
returnerr(debugfile, "retrImapMsg(%d) %s\n", sock, neterrstr());
|
||||
@@ -555,14 +446,14 @@ retrImapMsg(ptcx_t ptcx, SOCKET sock, int seqNum, int msgSize)
|
||||
|
||||
totalbytesread += bytesread;
|
||||
|
||||
bpos[bytesread] = 0;
|
||||
buffer[totalbytesread] = 0;
|
||||
|
||||
if (totalbytesread > msgSize) {
|
||||
/* search for end of response */
|
||||
if (strstr(buf, markerSingleLine)) {
|
||||
if (strstr(buffer, markerSingleLine)) {
|
||||
break;
|
||||
}
|
||||
if (strstr(buf, markerMultiLine)) {
|
||||
if (strstr(buffer, markerMultiLine)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -570,12 +461,10 @@ retrImapMsg(ptcx_t ptcx, SOCKET sock, int seqNum, int msgSize)
|
||||
D_PRINTF(debugfile,"Time expired while reading messages - in retrIMAP\n");
|
||||
break;
|
||||
}
|
||||
/* shift message over in buffer */
|
||||
memcpy(buf, bpos + bytesread - sizeof(markerMultiLine),
|
||||
sizeof(markerMultiLine));
|
||||
bpos = buf + sizeof(markerMultiLine);
|
||||
}
|
||||
|
||||
D_PRINTF(debugfile,"buffer=%s\n", buffer);
|
||||
|
||||
ptcx->bytesread += totalbytesread;
|
||||
|
||||
return totalbytesread;
|
||||
@@ -636,26 +525,7 @@ imapLogin(ptcx_t ptcx,
|
||||
gf_imapForceUniqueness = 0;
|
||||
|
||||
while (!done) {
|
||||
#if defined(IMAP_CAPABILITY) && !defined(SOCK_SSL)
|
||||
/*
|
||||
** don't do this if we tried STARTTLS above, since we already
|
||||
** did a CAPABILITY there...
|
||||
*/
|
||||
sprintf(command, "%d CAPABILITY" CRLF, ++pIMAP->seq_num);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
ret = doImapCommandResponse(ptcx, sock, pIMAP->seq_num,
|
||||
command, pIMAP->resp_buffer,
|
||||
sizeof(pIMAP->resp_buffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (ret == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->cmd.errs++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif /* IMAP_CAPABILITY && ! SOCK_SSL */
|
||||
|
||||
next_domain = rangeNext(&stats->domainRange, stats->lastDomain);
|
||||
next_domain = rangeNext(&stats->domainRange, stats->lastDomain);
|
||||
stats->lastDomain = next_domain;
|
||||
next_login = rangeNext(&stats->loginRange, stats->lastLogin);
|
||||
stats->lastLogin = next_login;
|
||||
@@ -889,51 +759,17 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
||||
char command[MAX_COMMAND_LEN];
|
||||
int numBytes = 0;
|
||||
long msgSize = 0;
|
||||
#if 0
|
||||
char *msgBuffer = NULL;
|
||||
int msgBufferSize = 0;
|
||||
#endif
|
||||
int rc;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
int leave_on_server;
|
||||
|
||||
char *p, *endp;
|
||||
|
||||
char newmsgs[MAX_RESPONSE_LEN];
|
||||
|
||||
/* if we're told to leave mail on server, do not delete the message */
|
||||
leave_on_server = (int)sample(pish->leaveMailOnServerDist);
|
||||
|
||||
if ( numRecent == 0 )
|
||||
return 0;
|
||||
|
||||
/* This actually finds the new messages. */
|
||||
sprintf(command, "%d SEARCH (NEW)" CRLF, ++pIMAP->seq_num);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doImapCommandResponse(ptcx, sock, pIMAP->seq_num,
|
||||
command, pIMAP->resp_buffer,
|
||||
sizeof(pIMAP->resp_buffer));
|
||||
event_stop (ptcx, &stats->cmd);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
if((p = strstr(pIMAP->resp_buffer, "SEARCH")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "IMAP: invalid SEARCH response: %s\n",
|
||||
pIMAP->resp_buffer);
|
||||
return -1;
|
||||
}
|
||||
p += strlen("SEARCH");
|
||||
|
||||
if((endp = strchr(p, '\n')) != NULL)
|
||||
*endp = 0;
|
||||
|
||||
/* response buffer overwritten by new IMAP commands, so save a copy */
|
||||
strcpy(newmsgs, p);
|
||||
p = newmsgs;
|
||||
|
||||
for(i = strtol(p, &p, 0); i != 0; i = strtol(p, &p, 0))
|
||||
{
|
||||
/* retr the msgs */
|
||||
for (i = numExists - numRecent + 1; i <= numExists; i++) {
|
||||
/* bail if time is up */
|
||||
if (gf_timeexpired >= EXIT_SOON) {
|
||||
D_PRINTF(debugfile,"Time expired while reading messages\n");
|
||||
@@ -945,8 +781,7 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
||||
++pIMAP->seq_num, i, CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doImapCommandResponse(ptcx, sock, pIMAP->seq_num,
|
||||
command, pIMAP->resp_buffer,
|
||||
sizeof(pIMAP->resp_buffer));
|
||||
command, pIMAP->resp_buffer, sizeof(pIMAP->resp_buffer));
|
||||
event_stop (ptcx, &stats->cmd);
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired >= EXIT_FAST) break; /* dont fall into error */
|
||||
@@ -955,28 +790,22 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
||||
|
||||
/* parse the SIZE out of buffer */
|
||||
if (!sscanf(pIMAP->resp_buffer, "* %*d FETCH (RFC822.SIZE %ld)", &msgSize)) {
|
||||
returnerr(debugfile,
|
||||
"IMAP4 Error parsing size of msg from response, %s: %s\n",
|
||||
returnerr(debugfile, "IMAP4 Error parsing size of msg from response, %s: %s\n",
|
||||
pIMAP->resp_buffer, neterrstr());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Sean O'Rourke: we used to allocate a message-size buffer here. Don't
|
||||
do that, since we don't care about message contents,
|
||||
anyways. */
|
||||
#if 0
|
||||
|
||||
/* malloc buffer for msg, with room for control (flags) info */
|
||||
msgBufferSize = msgSize+1024;
|
||||
msgBuffer = (char *) xcalloc(msgBufferSize);
|
||||
#endif /* 0 */
|
||||
msgBuffer = (char *) mycalloc(msgBufferSize);
|
||||
|
||||
/* FETCH the msg */
|
||||
sprintf(command, "%d FETCH %d (RFC822)%s", ++pIMAP->seq_num, i, CRLF);
|
||||
event_start(ptcx, &stats->msgread);
|
||||
numBytes = sendCommand(ptcx, sock, command);
|
||||
if (numBytes == -1) {
|
||||
event_stop(ptcx, &stats->msgread);
|
||||
#if 0
|
||||
xfree(msgBuffer);
|
||||
#endif
|
||||
myfree(msgBuffer);
|
||||
if (gf_timeexpired >= EXIT_FAST) break; /* dont fall into error */
|
||||
stats->msgread.errs++;
|
||||
returnerr(debugfile, "IMAP4 Error sending [%s] command: %s\n",
|
||||
@@ -985,24 +814,11 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
||||
}
|
||||
|
||||
/* read msg */
|
||||
#if 0
|
||||
numBytes = retrImapMsg(ptcx, sock, pIMAP->seq_num,
|
||||
msgBuffer, msgSize, msgBufferSize);
|
||||
#else
|
||||
if (pish->genChecksum == CS_NONE)
|
||||
numBytes = retrImapMsg(ptcx, sock, pIMAP->seq_num, msgSize);
|
||||
else {
|
||||
char term[20];
|
||||
/* XXX: is this actually what's done? */
|
||||
snprintf(term, sizeof(term), CRLF "%d ", pIMAP->seq_num);
|
||||
numBytes = cs_retrieve(ptcx, sock, CRLF CRLF, term);
|
||||
}
|
||||
#endif
|
||||
event_stop(ptcx, &stats->msgread);
|
||||
if (numBytes < 0) {
|
||||
#if 0
|
||||
xfree(msgBuffer);
|
||||
#endif
|
||||
if (numBytes <= 0) {
|
||||
myfree(msgBuffer);
|
||||
if (gf_timeexpired >= EXIT_FAST) break; /* dont fall into error */
|
||||
stats->msgread.errs++;
|
||||
returnerr(debugfile, "IMAP4 Error retrieving msg %d: %s\n",
|
||||
@@ -1010,24 +826,7 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
||||
return -1;
|
||||
}
|
||||
|
||||
T_PRINTF(ptcx->logfile, command,
|
||||
strlen (command), "IMAP4 SendCommand");
|
||||
|
||||
#if 0
|
||||
xfree(msgBuffer);
|
||||
#endif
|
||||
|
||||
#ifdef MSG_READ_TIME
|
||||
/* wait while "user" reads message */
|
||||
if (pish->msgReadTime) {
|
||||
int read_time = sample(pish->msgReadTime);
|
||||
if (read_time > 0) {
|
||||
event_start(ptcx, &ptimer->idle);
|
||||
MS_idle(ptcx, read_time);
|
||||
event_stop(ptcx, &ptimer->idle);
|
||||
}
|
||||
}
|
||||
#endif /* MSG_READ_TIME */
|
||||
myfree(msgBuffer);
|
||||
|
||||
/* send a NOOP */
|
||||
sprintf(command, "%d NOOP%s",++pIMAP->seq_num, CRLF);
|
||||
@@ -1043,8 +842,7 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
||||
|
||||
/* if we're told to leave mail on server, do not delete the message */
|
||||
if (!(pish->flags & leaveMailUnseen)) {
|
||||
if (pish->flags & leaveMailOnServer && /* just mark seen */
|
||||
(leave_on_server > 0)) {
|
||||
if (pish->flags & leaveMailOnServer) { /* just mark seen */
|
||||
/* mark the msg \seen needed??? */
|
||||
sprintf(command, "%d STORE %d +FLAGS (\\SEEN)%s",
|
||||
++pIMAP->seq_num,i, CRLF);
|
||||
@@ -1068,8 +866,7 @@ imapRetrRecentMessages(ptcx_t ptcx,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(pish->flags & leaveMailOnServer) || /* expunge if we are deleting */
|
||||
(leave_on_server == 0)) {
|
||||
if (!(pish->flags & leaveMailOnServer)) { /* expunge if we are deleting */
|
||||
/* EXPUNGE \deleted messages */
|
||||
sprintf(command, "%d EXPUNGE%s", ++pIMAP->seq_num, CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
@@ -1121,8 +918,17 @@ imapComputeSearchSchedule(ptcx_t ptcx, mail_command_t *cmd, int **searchSchedule
|
||||
|
||||
D_PRINTF(debugfile,"num searches to perform=%d\n", numSearches);
|
||||
|
||||
*searchSchedule = (int *) xcalloc(numSearches*sizeof(int));
|
||||
/* malloc the searchSchedule array */
|
||||
*searchSchedule = (int *) mycalloc(numSearches*sizeof(int));
|
||||
D_PRINTF(debugfile,"searchSchedule=%ld\n", *searchSchedule);
|
||||
|
||||
if (!*searchSchedule) {
|
||||
returnerr(debugfile, "IMAP4 Error, could not malloc searchSchedule: %s\n",neterrstr());
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(*searchSchedule, 0, numSearches*sizeof(int));
|
||||
|
||||
/* fill in the schedule, ordering the array */
|
||||
for (i = 0; i < numSearches; i++) {
|
||||
ran = (RANDOM() % (gt_testtime <= 8*60*60 ? 8*60*60 : gt_testtime));
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -38,21 +37,18 @@
|
||||
*/
|
||||
|
||||
#include "bench.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* really globalize variables */
|
||||
volatile int gf_timeexpired = 0;
|
||||
time_t gt_testtime = 0; /* time of test, in seconds */
|
||||
time_t gt_startedtime = 0; /* when we started */
|
||||
volatile time_t gt_shutdowntime = 0; /* startedtime + testtime */
|
||||
time_t gt_stopinterval = 0; /* MAX (ramptime/5, 10) */
|
||||
time_t gt_aborttime = 0; /* startedtime + testtime + ramptime */
|
||||
time_t gt_stopinterval = 0; /* MAX (ramptime/5, 10) */
|
||||
time_t gt_aborttime = 0; /* startedtime + testtime + ramptime*/
|
||||
|
||||
#ifdef USE_EVENTS
|
||||
int gf_use_events = 0;
|
||||
#endif
|
||||
int gn_record_telemetry = 0;
|
||||
int gn_total_weight = 0;
|
||||
int gn_client_throttle = 0;
|
||||
int gn_maxerrorcnt = 0;
|
||||
int gn_maxBlockCnt = 0;
|
||||
int gn_numprocs = 0;
|
||||
@@ -81,7 +77,7 @@ protocol_t g_protocols[] = { /* array of protocol information */
|
||||
pishStatsUpdate,
|
||||
pishStatsOutput,
|
||||
},
|
||||
{ /* Old POP -- 1 thread == 1 user */
|
||||
{
|
||||
"POP3",
|
||||
Pop3ParseStart,
|
||||
Pop3ParseEnd,
|
||||
@@ -93,30 +89,6 @@ protocol_t g_protocols[] = { /* array of protocol information */
|
||||
pishStatsUpdate,
|
||||
pishStatsOutput,
|
||||
},
|
||||
{ /* new POP -- 1 thread == N users */
|
||||
"MULTIPOP",
|
||||
MPopParseStart,
|
||||
MPopParseEnd,
|
||||
MPopCheckStart,
|
||||
MPopCheck,
|
||||
MPopCheckEnd,
|
||||
pishStatsFormat,
|
||||
pishStatsInit,
|
||||
pishStatsUpdate,
|
||||
pishStatsOutput,
|
||||
},
|
||||
{ /* mailspinner / SMMS webmail */
|
||||
"WEB",
|
||||
WebmailParseStart,
|
||||
WebmailParseEnd,
|
||||
doWebmailStart,
|
||||
doWebmailLoop,
|
||||
doWebmailEnd,
|
||||
pishStatsFormat,
|
||||
pishStatsInit,
|
||||
pishStatsUpdate,
|
||||
pishStatsOutput,
|
||||
},
|
||||
{
|
||||
"IMAP4",
|
||||
Imap4ParseStart,
|
||||
@@ -179,7 +151,8 @@ usage(const char *progname)
|
||||
fprintf(stderr, "Usage: %s [options] -n <clients> -t <time> <-s | -u <commandFile>>\n\n",
|
||||
progname);
|
||||
fprintf(stderr, " required parameters:\n");
|
||||
fprintf(stderr, " -n numprocs number of clients processes to run\n");
|
||||
fprintf(stderr, " -n numprocs number of clients processes to run [1-%d]\n",
|
||||
MAXPROCSPERNODE);
|
||||
fprintf(stderr, " -t testtime test duration (mins) or #[hmsd]\n");
|
||||
fprintf(stderr, " -s use stdin for commands\n");
|
||||
fprintf(stderr, " -u commandlist file for commands\n\n");
|
||||
@@ -188,13 +161,11 @@ usage(const char *progname)
|
||||
fprintf(stderr, " -h help - this message\n\n");
|
||||
fprintf(stderr, " -H name hostname for parsing HOSTS=\n");
|
||||
fprintf(stderr, " -A use abortive close\n");
|
||||
fprintf(stderr, " -T opsperhour client throttle\n");
|
||||
fprintf(stderr, " -f summpersec frequency to send summary results\n");
|
||||
fprintf(stderr, " -d debug\n");
|
||||
fprintf(stderr, " -D datestamp assign a datestamp\n");
|
||||
fprintf(stderr, " -N numthreads number of clients threads per process\n");
|
||||
#ifdef USE_EVENTS
|
||||
fprintf(stderr, " -e use event-queue model\n");
|
||||
#endif /* USE_EVENTS */
|
||||
fprintf(stderr, " -m maxErrorCnt threshold to force test abort\n");
|
||||
fprintf(stderr, " -M maxBlockCnt number of blocks to run\n");
|
||||
fprintf(stderr, " -R ramptime test rampup time (secs)\n");
|
||||
@@ -215,24 +186,23 @@ parseArgs(int argc, char **argv)
|
||||
*/
|
||||
|
||||
while((getoptch =
|
||||
getopt(argc,argv,"hf:H:t:u:c:m:M:n:N:R:D:Adrsve")) != EOF)
|
||||
getopt(argc,argv,"hf:H:T:t:u:c:m:M:n:N:R:D:Adrsv")) != EOF)
|
||||
{
|
||||
switch(getoptch)
|
||||
{
|
||||
#ifdef USE_EVENTS
|
||||
case 'e':
|
||||
gf_use_events = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
break;
|
||||
case 'H': /* name for parsing */
|
||||
gs_parsename = xstrdup(optarg);
|
||||
gs_parsename = mystrdup(optarg);
|
||||
break;
|
||||
case 'A':
|
||||
gf_abortive_close = 1;
|
||||
break;
|
||||
case 'T':
|
||||
/* client throttles to ops/hour */
|
||||
gn_client_throttle = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
/* feedback frequency in seconds */
|
||||
gn_feedback_secs = atoi(optarg);
|
||||
@@ -256,7 +226,7 @@ parseArgs(int argc, char **argv)
|
||||
gn_numthreads = atoi(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
commandsfilename = xstrdup(optarg);
|
||||
commandsfilename = mystrdup(optarg);
|
||||
break;
|
||||
case 's':
|
||||
f_usestdin = 1;
|
||||
@@ -332,7 +302,8 @@ resolve_addrs(char *host,
|
||||
phe = gethostbyname(host);
|
||||
#endif
|
||||
|
||||
if (phe == NULL) {
|
||||
if (phe == NULL)
|
||||
{
|
||||
D_PRINTF(stderr, "Gethostbyname failed: %s", neterrstr() );
|
||||
return(returnerr(stderr,"Can't get %s host entry\n", host));
|
||||
}
|
||||
@@ -347,38 +318,38 @@ resolve_addrs(char *host,
|
||||
ppe = getprotobyname(protocol);
|
||||
#endif
|
||||
|
||||
if (ppe == 0) {
|
||||
if (ppe == 0)
|
||||
{
|
||||
D_PRINTF(stderr, "protobyname returned %d\n", ppe );
|
||||
return(returnerr(stderr,"Can't get %s protocol entry\n",protocol));
|
||||
}
|
||||
memcpy(proto_ppe, ppe, sizeof(struct protoent));
|
||||
|
||||
/* D_PRINTF(stderr, "Protocol number %d\n", ppe->p_proto ); */
|
||||
|
||||
/* Use protocol to choose a socket type */
|
||||
if (strcmp(protocol,"udp") == 0)
|
||||
{
|
||||
*type = SOCK_DGRAM;
|
||||
}
|
||||
else
|
||||
{
|
||||
*type = SOCK_STREAM;
|
||||
/* D_PRINTF(stderr, "Choosing SOCK_STREAM %d type %d %s\n",
|
||||
SOCK_STREAM, *type, neterrstr() ); */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* connect to a socket given the hostname and protocol */
|
||||
|
||||
/*
|
||||
** XXX Sean O'Rourke: Note that this is used both for client connections to
|
||||
** the mailhost and for the communication channels between the
|
||||
** parent mailstone and its children. But it calls sock_open() at
|
||||
** the end, and returns a SOCKET (e.g. with possible linespeed, SSL,
|
||||
** etc.). Just extract the fd (with SOCK_FD()) for non-simulation use.
|
||||
*/
|
||||
|
||||
SOCKET
|
||||
connectSocket(ptcx_t ptcx,
|
||||
resolved_addr_t *hostInfo,
|
||||
char *protocol)
|
||||
{
|
||||
struct sockaddr_in sin; /* an Internet endpoint address */
|
||||
_SOCKET s; /* socket descriptor */
|
||||
SOCKET s; /* socket descriptor */
|
||||
int type; /* socket type */
|
||||
short proto;
|
||||
int returnval; /* temporary return value */
|
||||
@@ -389,8 +360,10 @@ connectSocket(ptcx_t ptcx,
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
memset((char *)&sin, 0, sizeof(sin));
|
||||
D_PRINTF(debugfile, "Zeroed address structure\n" );
|
||||
|
||||
sin.sin_port = htons(hostInfo->portNum);
|
||||
D_PRINTF(debugfile, "Set port number %d\n", hostInfo->portNum);
|
||||
|
||||
/* check if we've resolved this already */
|
||||
if ((hostInfo) && (hostInfo->resolved)) {
|
||||
@@ -406,9 +379,8 @@ connectSocket(ptcx_t ptcx,
|
||||
|
||||
if (resolve_addrs(hostInfo->hostName, "tcp",
|
||||
&host_phe, &host_ppe, &host_addr, &host_type)) {
|
||||
(void) returnerr(debugfile,"Can't resolve hostname %s in get()\n",
|
||||
return returnerr(debugfile,"Can't resolve hostname %s in get()\n",
|
||||
hostInfo->hostName);
|
||||
return BADSOCKET_VALUE;
|
||||
}
|
||||
sin.sin_addr.S_ADDR = host_addr;
|
||||
sin.sin_family = PF_INET;
|
||||
@@ -418,41 +390,47 @@ connectSocket(ptcx_t ptcx,
|
||||
|
||||
/* Allocate a socket */
|
||||
s = socket(PF_INET, type, proto);
|
||||
if (_BADSOCKET(s)) {
|
||||
int save_errno = errno;
|
||||
|
||||
if (BADSOCKET(s))
|
||||
{
|
||||
D_PRINTF(debugfile, "Can't create socket: %s\n",neterrstr() );
|
||||
_NETCLOSE(s);
|
||||
errno = save_errno;
|
||||
return BADSOCKET_VALUE;
|
||||
}
|
||||
|
||||
/* Connect the socket */
|
||||
D_PRINTF(debugfile, "Connecting %d to %s:%d\n",
|
||||
s, safe_inet_ntoa(sin.sin_addr, ntoa_buf), ntohs(sin.sin_port));
|
||||
D_PRINTF(debugfile, "Trying to connect %d with size %d\n",
|
||||
s, sizeof(sin));
|
||||
D_PRINTF(debugfile, "Address is family %d, port %d, addr %s\n",
|
||||
sin.sin_family, ntohs(sin.sin_port),
|
||||
safe_inet_ntoa(sin.sin_addr, ntoa_buf) );
|
||||
|
||||
returnval = connect(s, (struct sockaddr *)&sin, sizeof(sin));
|
||||
|
||||
if (returnval < 0) {
|
||||
int err = GET_ERROR; /* preserve the error code */
|
||||
|
||||
D_PRINTF(debugfile, "Can't connect: %s\n", neterrstr() );
|
||||
_NETCLOSE(s);
|
||||
NETCLOSE(s);
|
||||
|
||||
SET_ERROR(err);
|
||||
return BADSOCKET_VALUE;
|
||||
}
|
||||
|
||||
return sock_open(s);
|
||||
/* all done, returning socket descriptor */
|
||||
D_PRINTF(debugfile, "Returning %d from connectSocket call\n", s );
|
||||
return(s);
|
||||
|
||||
} /* END connectSocket() */
|
||||
|
||||
int
|
||||
set_abortive_close(SOCKET sock)
|
||||
{
|
||||
struct linger linger_opt;
|
||||
int _sock = SOCK_FD(sock);
|
||||
|
||||
linger_opt.l_onoff = 1;
|
||||
linger_opt.l_linger = 0;
|
||||
|
||||
if (setsockopt(_sock, SOL_SOCKET, SO_LINGER,
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_LINGER,
|
||||
(char *) &linger_opt, sizeof(linger_opt)) < 0) {
|
||||
returnerr(stderr, "Couldn't set SO_LINGER = 0\n");
|
||||
return -1;
|
||||
@@ -489,7 +467,7 @@ initializeCommands(char *cfilename)
|
||||
while (!feof(cfile)) { /* read file in to char array */
|
||||
if ((cbuflen + CMDBUF_INCR + 1) > cbufalloced) { /* grow array */
|
||||
cbufalloced += CMDBUF_INCR;
|
||||
cbuf = (char *)xrealloc(cbuf, cbufalloced+1);
|
||||
cbuf = (char *)myrealloc(cbuf, cbufalloced+1);
|
||||
cbuf[cbuflen] = '\0';
|
||||
}
|
||||
ret = fread(cbuf+cbuflen, 1, CMDBUF_INCR, cfile);
|
||||
@@ -508,6 +486,8 @@ initializeCommands(char *cfilename)
|
||||
if (cfile != stdin)
|
||||
fclose(cfile);
|
||||
|
||||
/* D_PRINTF(stderr, "Got commands len=%d:\n%s\n", cbuflen, cbuf); */
|
||||
|
||||
/* Read commands into structure, make sure we have all req arguments */
|
||||
if ((gn_total_weight = load_commands(cbuf)) < 0) {
|
||||
D_PRINTF(stderr, "could not load %s\n", cfilename);
|
||||
@@ -517,7 +497,6 @@ initializeCommands(char *cfilename)
|
||||
D_PRINTF(stderr, "No commands found for this host in %s\n", cfilename);
|
||||
errexit(stderr, "No command for current host in command file\n");
|
||||
}
|
||||
xfree(cbuf);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -533,13 +512,14 @@ readwriteStream(int ii, int fdin, int fdout)
|
||||
/* structured as a while() for future nonblocking style */
|
||||
while (toread) {
|
||||
errno = 0;
|
||||
res = _NETREAD(fdin, buf, sizeof(buf)-1);
|
||||
res = NETREAD(fdin, buf, sizeof(buf)-1);
|
||||
D_PRINTF(stderr, "read %d bytes from client %d\n", res, ii);
|
||||
if (res == 0) {
|
||||
return -1; /* EOF unless O_NDELAY */
|
||||
} else if (res < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
if (errno == EINTR || errno == EINTR) {
|
||||
return 0; /* go back to the poll loop to service others */
|
||||
}
|
||||
|
||||
fprintf(stderr, "readwriteStream(%d,%d,%d) error reading: errno=%d: %s\n",
|
||||
ii, fdin, fdout, errno, strerror(errno));
|
||||
@@ -552,6 +532,7 @@ readwriteStream(int ii, int fdin, int fdout)
|
||||
cp = buf;
|
||||
towrite = res;
|
||||
buf[towrite] = '\0';
|
||||
/*D_PRINTF(stderr, "writing %d bytes to %d [%s]\n", towrite, fdout, buf);*/
|
||||
D_PRINTF(stderr, "writing %d bytes to %d\n", towrite, fdout);
|
||||
while (towrite) {
|
||||
res = write(fdout, cp, towrite);
|
||||
@@ -598,9 +579,9 @@ readwriteChildren(pccx_t pccxs)
|
||||
* Wait for all children to exit.
|
||||
*/
|
||||
nfds=0;
|
||||
pfds = (struct pollfd *)xcalloc(sizeof(struct pollfd)*gn_numprocs);
|
||||
pfds = (struct pollfd *)mycalloc(sizeof(struct pollfd)*gn_numprocs);
|
||||
for (ii=0; ii < gn_numprocs; ++ii) {
|
||||
if (pccxs[ii].socket != _BADSOCKET_VALUE) {
|
||||
if (pccxs[ii].socket != -1) {
|
||||
pfds[nfds].fd = pccxs[ii].socket;
|
||||
++nfds;
|
||||
}
|
||||
@@ -621,9 +602,9 @@ readwriteChildren(pccx_t pccxs)
|
||||
pfds[ii].revents = 0;
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "entering poll(nfds=%d)\n", nfds);
|
||||
ret = poll(pfds, nfds, 5*1000);
|
||||
D_PRINTF(stderr, "back from poll, nfds = %d, ret=%d\n",
|
||||
nfds, ret);
|
||||
D_PRINTF(stderr, "back from poll, ret=%d\n", ret);
|
||||
|
||||
if (ret == 0)
|
||||
continue;
|
||||
@@ -645,8 +626,9 @@ readwriteChildren(pccx_t pccxs)
|
||||
}
|
||||
|
||||
if (pfds[ii].revents & POLLIN) {
|
||||
if (readwriteStream(ii, pfds[ii].fd, 1) == -1)
|
||||
if (readwriteStream(ii, pfds[ii].fd, 1) == -1) {
|
||||
closethisfd = 1;
|
||||
}
|
||||
} else if (pfds[ii].revents & (POLLHUP | POLLERR | POLLNVAL)) {
|
||||
if (pfds[ii].revents & POLLHUP)
|
||||
D_PRINTF(stderr, "POLLHUP for stdout fd=%d for client=%d!\n",
|
||||
@@ -657,7 +639,7 @@ readwriteChildren(pccx_t pccxs)
|
||||
if (closethisfd) {
|
||||
D_PRINTF(stderr, "closing for slot=%d fd=%d nfds=%d\n",
|
||||
ii, pfds[ii].fd, nfds);
|
||||
_NETCLOSE(pfds[ii].fd);
|
||||
NETCLOSE(pfds[ii].fd);
|
||||
|
||||
--nfds; /* shrink poll array */
|
||||
/* NOTE: this re-orders the array */
|
||||
@@ -676,7 +658,7 @@ readwriteChildren(pccx_t pccxs)
|
||||
nfds, time(0L), gt_shutdowntime);
|
||||
for (ii = 0; ii < nfds; ++ii) { /* close socket to make clients die */
|
||||
D_PRINTF(stderr, "closing for slot=%d fd=%d\n", ii, pfds[ii].fd);
|
||||
_NETCLOSE(pfds[ii].fd);
|
||||
NETCLOSE(pfds[ii].fd);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -688,7 +670,7 @@ readwriteChildren(pccx_t pccxs)
|
||||
THREAD_RET
|
||||
launchChild(void *targ)
|
||||
{
|
||||
_SOCKET clientsock;
|
||||
SOCKET clientsock;
|
||||
struct sockaddr_in saddr; /* server address */
|
||||
struct linger linger_opt;
|
||||
unsigned int testtimeleft;
|
||||
@@ -698,17 +680,18 @@ launchChild(void *targ)
|
||||
|
||||
gn_myPID = getpid();
|
||||
if (ramptime) {
|
||||
/* convert to microseconds */
|
||||
/* comvert to microseconds */
|
||||
if (gn_numthreads > 0) {
|
||||
/* force intermediate result to double to avoid overflow */
|
||||
thread_stagger_usec = (unsigned int)((ramptime * (double)USECINSEC) / gn_numthreads);
|
||||
thread_stagger_usec = (unsigned int)((ramptime * (double)USECINSEC) / gn_numthreads);
|
||||
} else {
|
||||
thread_stagger_usec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((clientsock=socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
if ((clientsock=socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
errexit(stderr, "child socket(): %s\n", neterrstr());
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_addr.S_ADDR = inet_addr("127.0.0.1");
|
||||
@@ -716,7 +699,7 @@ launchChild(void *targ)
|
||||
saddr.sin_port = listenport;
|
||||
|
||||
if (connect(clientsock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
|
||||
_NETCLOSE(clientsock);
|
||||
NETCLOSE(clientsock);
|
||||
errexit(stderr, "child connect(): %s\n", neterrstr());
|
||||
}
|
||||
#if 1
|
||||
@@ -724,7 +707,7 @@ launchChild(void *targ)
|
||||
linger_opt.l_linger = 60;
|
||||
|
||||
if (setsockopt(clientsock, SOL_SOCKET, SO_LINGER, (char *) &linger_opt, sizeof(linger_opt)) < 0) {
|
||||
_NETCLOSE(clientsock);
|
||||
NETCLOSE(clientsock);
|
||||
errexit(stderr, "child setsockopt(): %s\n", neterrstr());
|
||||
}
|
||||
#endif
|
||||
@@ -761,7 +744,7 @@ launchChild(void *targ)
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "child %d: closing logging socket\n", pnum);
|
||||
_NETCLOSE(clientsock);
|
||||
NETCLOSE(clientsock);
|
||||
|
||||
#ifndef _WIN32
|
||||
return((void *)ret);
|
||||
@@ -785,26 +768,20 @@ waitChildren(void)
|
||||
if (errno == ECHILD) {
|
||||
break; /* none left. finished */
|
||||
}
|
||||
else if (errno == EINTR) { /* alarm went off */
|
||||
if (errno == EINTR) { /* alarm went off */
|
||||
if (time(0L) > (gt_aborttime+(EXIT_FAST*gt_stopinterval))) {
|
||||
d_printf (stderr,
|
||||
"WARNING: Aborting wait for children!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
d_printf(stderr, "WARNING: wait(): %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (WIFSIGNALED (status)) { /* show error exits */
|
||||
d_printf (stderr, "Client pid %d died with signal %d\n",
|
||||
pid, WTERMSIG(status));
|
||||
} else {
|
||||
D_PRINTF(stderr, "Client pid %d: status: %d errno=%d: %s\n",
|
||||
pid, status, errno, strerror(errno));
|
||||
}
|
||||
if (WIFSIGNALED (status)) { /* show error exits */
|
||||
d_printf (stderr, "Client pid %d died with signal %d\n",
|
||||
pid, WTERMSIG(status));
|
||||
} else {
|
||||
D_PRINTF(stderr, "Client pid %d: status: %d errno=%d: %s\n",
|
||||
pid, status, errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif /* !_WIN32 */
|
||||
@@ -824,16 +801,10 @@ main(int argc, char *argv[])
|
||||
int ret;
|
||||
int pid=0;
|
||||
pccx_t pccxs; /* client process contexts */
|
||||
_SOCKET serversock;
|
||||
SOCKET serversock;
|
||||
struct sockaddr_in saddr; /* server address */
|
||||
struct sockaddr_in caddr; /* client address */
|
||||
/* XXX: Loathe AIX */
|
||||
#ifdef __AIX__
|
||||
# define SOCKLEN_T unsigned long
|
||||
#else
|
||||
# define SOCKLEN_T int
|
||||
#endif
|
||||
SOCKLEN_T addr_len;
|
||||
int addr_len;
|
||||
char ntoabuf[SIZEOF_NTOABUF];
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -850,10 +821,6 @@ main(int argc, char *argv[])
|
||||
#endif /* _WIN32 */
|
||||
|
||||
gn_myPID = getpid();
|
||||
|
||||
/* XXX: random seed should probably also be settable on command line. */
|
||||
srand48(time(0) ^ gn_myPID);
|
||||
|
||||
gethostname(gs_thishostname, sizeof(gs_thishostname)-1);
|
||||
|
||||
memset(mailmaster, 0, sizeof(mailmaster));
|
||||
@@ -889,8 +856,8 @@ main(int argc, char *argv[])
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
if (gn_numprocs < 1) {
|
||||
returnerr(stderr, "Number of clients must be between >= 1\n");
|
||||
if (gn_numprocs > MAXPROCSPERNODE || gn_numprocs < 1) {
|
||||
returnerr(stderr, "Number of clients must be between 1 and %d\n", MAXPROCSPERNODE);
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
@@ -911,32 +878,35 @@ main(int argc, char *argv[])
|
||||
gt_aborttime = gt_shutdowntime + gt_stopinterval*2*EXIT_FASTEST;
|
||||
|
||||
|
||||
pccxs = (pccx_t)xcalloc(sizeof(ccx_t) * gn_numprocs);
|
||||
if ((pccxs = (pccx_t)mycalloc(sizeof(ccx_t) * gn_numprocs)) == NULL) {
|
||||
errexit(stderr, "error mycalloc() pccxs\n");
|
||||
}
|
||||
|
||||
D_PRINTF(stderr, "preparing serversock\n");
|
||||
|
||||
if ((serversock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
if ((serversock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
errexit(stderr, "socket() error: %s\n", neterrstr());
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
|
||||
/*saddr.sin_addr.S_ADDR = htonl(INADDR_ANY);*/
|
||||
saddr.sin_addr.S_ADDR = inet_addr("127.0.0.1");
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = 0;
|
||||
|
||||
if (bind(serversock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
|
||||
_NETCLOSE(serversock);
|
||||
NETCLOSE(serversock);
|
||||
errexit(stderr, "bind() error: %s\n", neterrstr());
|
||||
}
|
||||
|
||||
if (listen(serversock, 512) == -1) {
|
||||
_NETCLOSE(serversock);
|
||||
NETCLOSE(serversock);
|
||||
errexit(stderr, "listen() error: %s\n", neterrstr());
|
||||
}
|
||||
|
||||
addr_len = sizeof(saddr);
|
||||
if (getsockname(serversock, (struct sockaddr *)&saddr, &addr_len) == -1) {
|
||||
_NETCLOSE(serversock);
|
||||
NETCLOSE(serversock);
|
||||
errexit(stderr, "getsockname() error: %s\n", neterrstr());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,317 +0,0 @@
|
||||
/*
|
||||
* Trivially modified by Sean O'Rourke for inclusion in mailstone.
|
||||
* Much too trivial for copyright.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Kurt D. Zeilenga for inclusion into OpenLDAP
|
||||
* I hereby disclaim copyright in any changes I have made; this
|
||||
* code remains in the public domain.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
|
||||
not require an integer type which is exactly 32 bits. This work
|
||||
draws on the changes for the same purpose by Tatu Ylonen
|
||||
<ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
|
||||
that code, there is no copyright issue. I hereby disclaim
|
||||
copyright in any changes I have made; this code remains in the
|
||||
public domain. */
|
||||
|
||||
#include "md5.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Little-endian byte-swapping routines. Note that these do not
|
||||
depend on the size of datatypes such as uint32, nor do they require
|
||||
us to detect the endianness of the machine we are running on. It
|
||||
is possible they should be macros for speed, but I would be
|
||||
surprised if they were a performance bottleneck for MD5. */
|
||||
|
||||
static uint32
|
||||
getu32( const unsigned char *addr )
|
||||
{
|
||||
return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
|
||||
| addr[1]) << 8 | addr[0];
|
||||
}
|
||||
|
||||
static void
|
||||
putu32( uint32 data, unsigned char *addr )
|
||||
{
|
||||
addr[0] = (unsigned char)data;
|
||||
addr[1] = (unsigned char)(data >> 8);
|
||||
addr[2] = (unsigned char)(data >> 16);
|
||||
addr[3] = (unsigned char)(data >> 24);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
void
|
||||
lutil_MD5Init( struct lutil_MD5Context *ctx )
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
void
|
||||
lutil_MD5Update(
|
||||
struct lutil_MD5Context *ctx,
|
||||
const unsigned char *buf,
|
||||
unsigned int len
|
||||
)
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = (t + ((uint32)len << 3)) & 0xffffffff) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if ( t ) {
|
||||
unsigned char *p = ctx->in + t;
|
||||
|
||||
t = 64-t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
lutil_MD5Transform(ctx->buf, ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in, buf, 64);
|
||||
lutil_MD5Transform(ctx->buf, ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void
|
||||
lutil_MD5Final( unsigned char *digest, struct lutil_MD5Context *ctx )
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
lutil_MD5Transform(ctx->buf, ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count-8);
|
||||
}
|
||||
|
||||
/* Append length in bits and transform */
|
||||
putu32(ctx->bits[0], ctx->in + 56);
|
||||
putu32(ctx->bits[1], ctx->in + 60);
|
||||
|
||||
lutil_MD5Transform(ctx->buf, ctx->in);
|
||||
putu32(ctx->buf[0], digest);
|
||||
putu32(ctx->buf[1], digest + 4);
|
||||
putu32(ctx->buf[2], digest + 8);
|
||||
putu32(ctx->buf[3], digest + 12);
|
||||
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
#ifndef ASM_MD5
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
void
|
||||
lutil_MD5Transform( uint32 *buf, const unsigned char *inraw )
|
||||
{
|
||||
register uint32 a, b, c, d;
|
||||
uint32 in[16];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i)
|
||||
in[i] = getu32 (inraw + 4 * i);
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TEST
|
||||
/* Simple test program. Can use it to manually run the tests from
|
||||
RFC1321 for example. */
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv )
|
||||
{
|
||||
struct lutil_MD5Context context;
|
||||
unsigned char checksum[16];
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
for (j = 1; j < argc; ++j)
|
||||
{
|
||||
printf ("MD5 (\"%s\") = ", argv[j]);
|
||||
lutil_MD5Init (&context);
|
||||
lutil_MD5Update (&context, argv[j], strlen (argv[j]));
|
||||
lutil_MD5Final (checksum, &context);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
printf ("%02x", (unsigned int) checksum[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST */
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Trivial modifications by Sean O'Rourke, Feb 2000, for inclusion in
|
||||
* Mailstone.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 1998,1999 The OpenLDAP Foundation, Redwood City, California, USA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms are permitted only
|
||||
* as authorized by the OpenLDAP Public License. A copy of this
|
||||
* license is available at http://www.OpenLDAP.org/license.html or
|
||||
* in file LICENSE in the top-level directory of the distribution.
|
||||
*/
|
||||
|
||||
/* See md5.c for explanation and copyright information. */
|
||||
|
||||
#ifndef _LUTIL_MD5_H_
|
||||
#define _LUTIL_MD5_H_
|
||||
|
||||
/* Unlike previous versions of this code, uint32 need not be exactly
|
||||
32 bits, merely 32 bits or more. Choosing a data type which is 32
|
||||
bits instead of 64 is not important; speed is considerably more
|
||||
important. ANSI guarantees that "unsigned long" will be big enough,
|
||||
and always using it seems to have few disadvantages. */
|
||||
|
||||
typedef unsigned long uint32;
|
||||
|
||||
struct lutil_MD5Context {
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
unsigned char in[64];
|
||||
};
|
||||
|
||||
void lutil_MD5Init(struct lutil_MD5Context *context);
|
||||
|
||||
void lutil_MD5Update(struct lutil_MD5Context *context,
|
||||
unsigned char const *buf,
|
||||
unsigned len);
|
||||
|
||||
void lutil_MD5Final(unsigned char digest[16],
|
||||
struct lutil_MD5Context *context);
|
||||
|
||||
void lutil_MD5Transform(uint32 buf[4],
|
||||
const unsigned char in[64]);
|
||||
|
||||
/*
|
||||
* This is needed to make RSAREF happy on some MS-DOS compilers.
|
||||
*/
|
||||
typedef struct lutil_MD5Context lutil_MD5_CTX;
|
||||
|
||||
#endif /* _LUTIL_MD5_H_ */
|
||||
@@ -1,562 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
#include "xalloc.h"
|
||||
#include "checksum.h"
|
||||
|
||||
/* flags definitions */
|
||||
#define leaveMailOnServer 0x01
|
||||
|
||||
/*
|
||||
** MPOP user structure
|
||||
**
|
||||
** each context is a NULL-terminated linked list of users.
|
||||
*/
|
||||
typedef struct _MPop {
|
||||
struct _MPop *next;
|
||||
char *login; /* login name (malloc()-allocated) */
|
||||
char *passwd; /* POP password (malloc()-allocated) */
|
||||
int old_msgs; /* messages in box at last check */
|
||||
int leave_on_server; /* 1 == don't DELE messages */
|
||||
} MPop;
|
||||
|
||||
/* POP RFC says responses are all <= 512 bytes including CRLF: */
|
||||
#define RESPLEN 512
|
||||
|
||||
/*
|
||||
** Functions implementing each protocol command
|
||||
*/
|
||||
|
||||
static int mpop_connect(ptcx_t , pish_command_t *, pish_stats_t *, MPop *);
|
||||
static int mpop_login(ptcx_t , pish_stats_t *, MPop *, pmail_command_t);
|
||||
static int mpop_uidl(ptcx_t , pish_stats_t *, MPop *);
|
||||
static int mpop_stat(ptcx_t , pish_stats_t *, MPop *);
|
||||
static int mpop_retr(ptcx_t , pish_stats_t *, MPop *, int );
|
||||
static int mpop_dele(ptcx_t , pish_stats_t *, MPop *, int );
|
||||
static int mpop_quit(ptcx_t , pish_command_t *, pish_stats_t *, MPop *);
|
||||
|
||||
/*
|
||||
** Internal utility functions
|
||||
*/
|
||||
|
||||
static int mpop_cmd_resp(ptcx_t , char *, char *, int );
|
||||
static int mpop_basic_cmd(ptcx_t , char *);
|
||||
static int mpop_multiline_cmd(ptcx_t , char *);
|
||||
static int mpop_simultaneous_users(pish_command_t *, pish_stats_t *);
|
||||
|
||||
static int
|
||||
mpop_cmd_resp(ptcx, cmd, resp, rlen)
|
||||
ptcx_t ptcx;
|
||||
char *cmd;
|
||||
char *resp;
|
||||
int rlen;
|
||||
{
|
||||
int len;
|
||||
SOCKET sock = ptcx->sock;
|
||||
|
||||
T_PRINTF(ptcx->logfile, cmd, strlen(cmd), "MPOP command");
|
||||
len = doCommandResponse(ptcx, sock, cmd, resp, rlen);
|
||||
if (len > 0 && resp[0] != '+') /* not "+OK..." */
|
||||
len = -1;
|
||||
|
||||
T_PRINTF(ptcx->logfile, resp, len, "MPOP response");
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_basic_cmd(ptcx, cmd)
|
||||
ptcx_t ptcx;
|
||||
char *cmd;
|
||||
{
|
||||
char dont_care_buf[RESPLEN];
|
||||
return mpop_cmd_resp(ptcx, cmd, dont_care_buf, sizeof(dont_care_buf));
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_connect(ptcx, pish, stats, mp)
|
||||
ptcx_t ptcx;
|
||||
pish_command_t *pish;
|
||||
pish_stats_t *stats;
|
||||
MPop *mp;
|
||||
{
|
||||
char buf[RESPLEN];
|
||||
int len;
|
||||
|
||||
ptcx->net_timeout = pish->net_timeout;
|
||||
|
||||
event_start(ptcx, &stats->connect);
|
||||
ptcx->sock = connectSocket(ptcx, &pish->hostInfo, "tcp");
|
||||
event_stop(ptcx, &stats->connect);
|
||||
if (BADSOCKET(ptcx->sock))
|
||||
{
|
||||
if (gf_timeexpired < EXIT_FAST)
|
||||
{
|
||||
stats->connect.errs++;
|
||||
returnerr(debugfile,
|
||||
"MPOP Couldn't connect to %s: %s\n",
|
||||
pish->hostInfo.hostName, neterrstr());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (gf_abortive_close)
|
||||
{
|
||||
if (set_abortive_close(ptcx->sock) != 0)
|
||||
{
|
||||
returnerr (debugfile,
|
||||
"MPOP: WARNING: Could not set abortive close\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
if (pish->sslTunnel)
|
||||
{
|
||||
SSL_INIT(ptcx->sock, pish);
|
||||
D_PRINTF(debugfile, "MPOP: initialized SSL tunneling.");
|
||||
}
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
LS_INIT(ptcx->sock, pish);
|
||||
|
||||
/* READ connect response from server */
|
||||
event_start(ptcx, &stats->banner);
|
||||
len = readResponse(ptcx, ptcx->sock, buf, sizeof(buf));
|
||||
event_stop(ptcx, &stats->banner);
|
||||
if (len <= 0)
|
||||
{
|
||||
if (gf_timeexpired < EXIT_FAST)
|
||||
{
|
||||
stats->banner.errs++;
|
||||
returnerr(debugfile,"MPOP Error reading banner: %s\n",
|
||||
neterrstr());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
T_PRINTF(ptcx->logfile, buf, len, "MPOP banner");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_login(ptcx, stats, mp, cmd)
|
||||
ptcx_t ptcx;
|
||||
pish_stats_t *stats;
|
||||
MPop *mp;
|
||||
pmail_command_t cmd;
|
||||
{
|
||||
int n;
|
||||
char buf[512]; /* big enough for "XXXX username@host\r\n" */
|
||||
#ifdef SOCK_SSL
|
||||
pish_command_t *pish = (pish_command_t*)cmd->data;
|
||||
if (!pish->useTLS)
|
||||
goto end_tls;
|
||||
|
||||
event_start(ptcx, &stats->cmd);
|
||||
n = mpop_cmd_resp(ptcx, "CAPA" CRLF, buf, sizeof(buf));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (n < 0)
|
||||
{
|
||||
stats->cmd.errs++;
|
||||
goto end_tls;
|
||||
}
|
||||
if (strstr(buf, "STLS") != NULL)
|
||||
{
|
||||
event_start(ptcx, &stats->cmd);
|
||||
n = mpop_basic_cmd(ptcx, "STLS" CRLF);
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (n < 0)
|
||||
stats->cmd.errs++;
|
||||
else
|
||||
SSL_INIT(ptcx->sock, cmd->data);
|
||||
}
|
||||
|
||||
end_tls:
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
event_start(ptcx, &stats->login);
|
||||
snprintf(buf, sizeof(buf), "USER %s" CRLF, mp->login);
|
||||
if ((n = mpop_basic_cmd(ptcx, buf) < 0))
|
||||
goto done;
|
||||
|
||||
snprintf(buf, sizeof(buf), "PASS %s" CRLF, mp->passwd);
|
||||
n = mpop_basic_cmd(ptcx, buf);
|
||||
done:
|
||||
if (n < 0)
|
||||
stats->login.errs++;
|
||||
event_stop(ptcx, &stats->login);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_stat(ptcx, stats, mp)
|
||||
ptcx_t ptcx;
|
||||
pish_stats_t *stats;
|
||||
MPop *mp;
|
||||
{
|
||||
char buf[RESPLEN];
|
||||
int len;
|
||||
int msgs = -1;
|
||||
int size = -1;
|
||||
|
||||
event_start(ptcx, &stats->cmd);
|
||||
if ((len = mpop_cmd_resp(ptcx, "STAT" CRLF, buf, sizeof(buf)-1)) < 0)
|
||||
goto done;
|
||||
buf[len] = '\0';
|
||||
sscanf(buf, "+OK %d %d", &msgs, &size);
|
||||
done:
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (msgs < 0)
|
||||
{
|
||||
D_PRINTF(debugfile,
|
||||
"Multipop: Error in STAT response `%s'\n", buf);
|
||||
stats->cmd.errs++;
|
||||
}
|
||||
return msgs;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_dele(ptcx, stats, mp, msgnum)
|
||||
ptcx_t ptcx;
|
||||
pish_stats_t *stats;
|
||||
MPop *mp;
|
||||
int msgnum;
|
||||
{
|
||||
char buf[64];
|
||||
int len;
|
||||
snprintf(buf, sizeof(buf), "DELE %d"CRLF, msgnum);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
len = mpop_basic_cmd(ptcx, buf);
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (len < 0)
|
||||
stats->cmd.errs++;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_quit(ptcx, pish, stats, mp)
|
||||
ptcx_t ptcx;
|
||||
pish_command_t *pish;
|
||||
pish_stats_t *stats;
|
||||
MPop *mp;
|
||||
{
|
||||
int len = 0;
|
||||
if (!sample(pish->dropRate))
|
||||
{
|
||||
event_start(ptcx, &stats->logout);
|
||||
len = mpop_basic_cmd(ptcx, "QUIT"CRLF);
|
||||
}
|
||||
if (!BADSOCKET(ptcx->sock))
|
||||
NETCLOSE(ptcx->sock);
|
||||
event_stop(ptcx, &stats->logout);
|
||||
|
||||
if (len < 0)
|
||||
stats->logout.errs++;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_multiline_cmd(ptcx, cmd)
|
||||
ptcx_t ptcx;
|
||||
char *cmd;
|
||||
{
|
||||
SOCKET sock = ptcx->sock;
|
||||
int len;
|
||||
int nread = 0;
|
||||
|
||||
char *EOM = CRLF"."CRLF;
|
||||
int EOM_LEN = strlen(CRLF"."CRLF);
|
||||
|
||||
char buf[4096];
|
||||
|
||||
if ((len = sendCommand(ptcx, ptcx->sock, cmd)) < 0)
|
||||
return -1;
|
||||
while ((len = retryRead(ptcx, ptcx->sock, buf, sizeof(buf))) <= 0)
|
||||
{
|
||||
if (len < 0)
|
||||
return -1;
|
||||
}
|
||||
if (buf[0] != '+')
|
||||
return -1;
|
||||
|
||||
nread += len;
|
||||
len -= EOM_LEN;
|
||||
|
||||
/* len is always EOM_LEN less than the amt of data present here */
|
||||
while (memcmp(buf + len, EOM, EOM_LEN) != 0)
|
||||
{
|
||||
memcpy(buf, buf + len, EOM_LEN);
|
||||
if ((len = retryRead(ptcx, sock, buf + EOM_LEN,
|
||||
sizeof(buf) - EOM_LEN)) < 0)
|
||||
return -1;
|
||||
ptcx->bytesread += len;
|
||||
nread += len;
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_retr(ptcx, stats, mp, msgnum)
|
||||
ptcx_t ptcx;
|
||||
pish_stats_t *stats;
|
||||
MPop *mp;
|
||||
int msgnum;
|
||||
{
|
||||
char cmd[64];
|
||||
int len;
|
||||
snprintf(cmd, 64, "RETR %d"CRLF, msgnum);
|
||||
event_start(ptcx, &stats->msgread);
|
||||
len = mpop_multiline_cmd(ptcx, cmd);
|
||||
event_stop(ptcx, &stats->msgread);
|
||||
if (len < 0)
|
||||
stats->msgread.errs++;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_uidl(ptcx, stats, mp)
|
||||
ptcx_t ptcx;
|
||||
pish_stats_t *stats;
|
||||
MPop *mp;
|
||||
{
|
||||
int len;
|
||||
event_start(ptcx, &stats->cmd);
|
||||
len = mpop_multiline_cmd(ptcx, "UIDL"CRLF);
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (len < 0)
|
||||
stats->cmd.errs++;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
mpop_simultaneous_users(pish, stats)
|
||||
pish_command_t *pish;
|
||||
pish_stats_t *stats;
|
||||
{
|
||||
int per_client = (stats->loginRange.span + 1)
|
||||
* (stats->domainRange.span + 1);
|
||||
double users = (double)per_client * pish->percentActive;
|
||||
return (int)rint(users);
|
||||
}
|
||||
|
||||
/*
|
||||
** External routines
|
||||
*/
|
||||
|
||||
int
|
||||
MPopParseStart(cmd, line, defparm)
|
||||
pmail_command_t cmd;
|
||||
char *line;
|
||||
param_list_t *defparm;
|
||||
{
|
||||
int ret = Pop3ParseStart(cmd, line, defparm);
|
||||
pish_command_t *pish = (pish_command_t*)cmd->data;
|
||||
pish->percentActive = 1.0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
MPopParseEnd(cmd, section, defparm)
|
||||
pmail_command_t cmd;
|
||||
string_list_t *section;
|
||||
param_list_t *defparm;
|
||||
{
|
||||
pish_command_t *pish;
|
||||
if (!Pop3ParseEnd(cmd, section, defparm))
|
||||
return returnerr(stderr, "Multipop: POP parse error\n");
|
||||
pish = (pish_command_t*)cmd->data;
|
||||
if (pish->percentActive == 0)
|
||||
return returnerr(stderr,
|
||||
"Multipop: percentActive == 0\n");
|
||||
if (pish->userSpacing == NULL)
|
||||
return returnerr(stderr,
|
||||
"Multipop: missing userSpacing\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
MPopCheck(ptcx, cmd, ptimer, ptr)
|
||||
ptcx_t ptcx;
|
||||
pmail_command_t cmd;
|
||||
cmd_stats_t *ptimer;
|
||||
void *ptr;
|
||||
{
|
||||
int new_msgs;
|
||||
int start_time, user_spacing;
|
||||
int i = 0;
|
||||
MPop *mp;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
|
||||
for (mp = (MPop*)ptr; mp != NULL; mp = mp->next)
|
||||
{
|
||||
int nnew;
|
||||
D_PRINTF(debugfile, "Multipop[%d]: begin check for `%s'\n",
|
||||
ptcx->threadnum, mp->login);
|
||||
|
||||
start_time = time(0);
|
||||
if (mpop_connect(ptcx, pish, stats, mp) < 0)
|
||||
continue; /* failed connect => try next user */
|
||||
|
||||
if (mpop_login(ptcx, stats, mp, cmd) < 0)
|
||||
goto checkdone;
|
||||
|
||||
if ((new_msgs = mpop_stat(ptcx, stats, mp)) < 0)
|
||||
goto checkdone;
|
||||
|
||||
if (new_msgs > 0 && mp->leave_on_server)
|
||||
mpop_uidl(ptcx, stats, mp);
|
||||
|
||||
nnew = new_msgs - mp->old_msgs;
|
||||
for (i = mp->old_msgs; i < new_msgs; i++)
|
||||
{
|
||||
/* NOTE: POP starts counting at 1, it appears */
|
||||
int msgnum = i + 1;
|
||||
|
||||
if (pish->genChecksum == CS_NONE)
|
||||
{
|
||||
if (mpop_retr(ptcx, stats, mp, msgnum) < 0)
|
||||
goto checkdone;
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[32];
|
||||
int ret;
|
||||
snprintf(buf, sizeof(buf), "RETR %d" CRLF,
|
||||
msgnum);
|
||||
ret = cs_retrieve(ptcx, ptcx->sock, CRLF CRLF,
|
||||
CRLF "." CRLF);
|
||||
if (ret < 0)
|
||||
goto checkdone;
|
||||
}
|
||||
|
||||
if (mp->leave_on_server == 0)
|
||||
{
|
||||
if (mpop_dele(ptcx, stats, mp, msgnum) < 0)
|
||||
goto checkdone;
|
||||
}
|
||||
else
|
||||
mp->old_msgs++;
|
||||
}
|
||||
|
||||
D_PRINTF(debugfile, "Multipop[%d]: %d messages for `%s'\n",
|
||||
ptcx->threadnum, nnew, mp->login);
|
||||
checkdone:
|
||||
mpop_quit(ptcx, pish, stats, mp);
|
||||
user_spacing = sample(pish->userSpacing);
|
||||
if (user_spacing > 0 && mp->next != NULL)
|
||||
{
|
||||
user_spacing -= (time(0) - start_time)*1000;
|
||||
if (user_spacing > 0)
|
||||
MS_idle(ptcx, user_spacing);
|
||||
else
|
||||
D_PRINTF(debugfile,
|
||||
"Warning: multipop behind by %d\n",
|
||||
-user_spacing);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
MPopCheckStart(ptcx, cmd, ptimer)
|
||||
ptcx_t ptcx;
|
||||
pmail_command_t cmd;
|
||||
cmd_stats_t *ptimer;
|
||||
{
|
||||
int domain, login;
|
||||
int len;
|
||||
int i;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
int users = mpop_simultaneous_users(pish, stats);
|
||||
MPop *mp = NULL;
|
||||
|
||||
D_PRINTF(debugfile, "Multipop[%d]: %d users per block\n",
|
||||
ptcx->threadnum, users);
|
||||
|
||||
for (i = 0; i < users; i++)
|
||||
{
|
||||
/* set up our identity */
|
||||
MPop *temp = XALLOC(struct _MPop);
|
||||
temp->next = mp;
|
||||
mp = temp;
|
||||
|
||||
domain = rangeNext(&stats->domainRange, stats->lastDomain);
|
||||
stats->lastDomain = domain;
|
||||
login = rangeNext (&stats->loginRange, stats->lastLogin);
|
||||
stats->lastLogin = login;
|
||||
|
||||
len = strlen(pish->loginFormat) + 10;
|
||||
temp->login = xalloc(len);
|
||||
snprintf(temp->login, len, pish->loginFormat, login, domain);
|
||||
|
||||
len = strlen(pish->passwdFormat) + 10;
|
||||
temp->passwd = xalloc(len);
|
||||
snprintf(temp->passwd, len, pish->passwdFormat, login);
|
||||
|
||||
temp->old_msgs = 0;
|
||||
temp->leave_on_server = pish->flags & leaveMailOnServer;
|
||||
}
|
||||
/* assert(mp != NULL); */
|
||||
D_PRINTF(debugfile, "Multipop[%d]: first check\n", ptcx->threadnum);
|
||||
if (mp == NULL)
|
||||
fprintf(stderr, "Multipop[%d]: no users!\n", ptcx->threadnum);
|
||||
else
|
||||
MPopCheck(ptcx, cmd, ptimer, mp);
|
||||
return mp;
|
||||
}
|
||||
|
||||
void
|
||||
MPopCheckEnd(ptcx, cmd, ptimer, ptr)
|
||||
ptcx_t ptcx;
|
||||
pmail_command_t cmd;
|
||||
cmd_stats_t *ptimer;
|
||||
void *ptr;
|
||||
{
|
||||
MPop *mp = (MPop*)ptr;
|
||||
D_PRINTF(debugfile, "Multipop[%d]: last check\n", ptcx->threadnum);
|
||||
MPopCheck(ptcx, cmd, ptimer, ptr);
|
||||
while (mp != NULL)
|
||||
{
|
||||
MPop *tmp = mp;
|
||||
mp = mp->next;
|
||||
xfree(tmp->login);
|
||||
xfree(tmp->passwd);
|
||||
xfree(tmp);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -39,7 +38,6 @@
|
||||
*/
|
||||
|
||||
#include "bench.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* global variables */
|
||||
param_list_t *g_default_params; /* list of default values */
|
||||
@@ -61,43 +59,6 @@ protocol_get (char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** SIZE_ATOF(tok) -- convert a string Nx to bytes
|
||||
**
|
||||
** x is 'm' for megabytes, 'k' for kilobytes, or 'b' for bytes
|
||||
*/
|
||||
double
|
||||
size_atof(tok)
|
||||
const char *tok;
|
||||
{
|
||||
char *endptr;
|
||||
double ret;
|
||||
if(*tok == '\0')
|
||||
{
|
||||
fprintf(stderr, "Empty value in size_atof.\n");
|
||||
exit(-1);
|
||||
}
|
||||
ret = strtod(tok, &endptr);
|
||||
while(*endptr && isspace(*endptr))
|
||||
endptr++;
|
||||
switch(*endptr)
|
||||
{
|
||||
case 'b': case 'B':
|
||||
case '\0':
|
||||
break;
|
||||
case 'k': case 'K':
|
||||
ret *= 1024;
|
||||
break;
|
||||
case 'M': case 'm':
|
||||
ret *= 1024 * 1024;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid size specifier '%s'\n", endptr);
|
||||
exit(-1);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
converts a string of the form #x to seconds
|
||||
where x can be a unit specifier of
|
||||
@@ -136,46 +97,6 @@ time_atoi(const char *pstr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
converts a string of the form #x to milliseconds
|
||||
where x can be a unit specifier of
|
||||
d or D days
|
||||
h or H hours
|
||||
m or M minutes
|
||||
s or S seconds
|
||||
the default is seconds
|
||||
*/
|
||||
int
|
||||
millitime_atoi(const char *pstr)
|
||||
{
|
||||
int ret=0;
|
||||
int len = strlen(pstr);
|
||||
|
||||
if (!pstr[0]) return 0;
|
||||
switch (pstr[len-1]) {
|
||||
case 'd': /* days */
|
||||
case 'D':
|
||||
ret = 24 * 60 * 60 * 1000 * atoi(pstr);
|
||||
break;
|
||||
case 'h': /* hours */
|
||||
case 'H':
|
||||
ret = 60 * 60 * 1000 * atoi(pstr);
|
||||
break;
|
||||
case 'm': /* minutes */
|
||||
case 'M':
|
||||
ret = 60 * 1000 * atoi(pstr);
|
||||
break;
|
||||
case 's': /* seconds */
|
||||
case 'S':
|
||||
ret = 1000 * atoi(pstr);
|
||||
break;
|
||||
default:
|
||||
ret = atoi(pstr);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
Simple keyword indexed string storage
|
||||
This kind of thing has been invented many times. Once more with gusto!
|
||||
@@ -183,7 +104,7 @@ millitime_atoi(const char *pstr)
|
||||
param_list_t *
|
||||
paramListInit (void)
|
||||
{
|
||||
param_list_t *np = XCALLOC (struct param_list);
|
||||
param_list_t *np = (param_list_t *)mycalloc (sizeof (param_list_t));
|
||||
return np;
|
||||
}
|
||||
|
||||
@@ -199,26 +120,32 @@ paramListAdd (param_list_t *list,
|
||||
assert (name != NULL);
|
||||
assert (value != NULL);
|
||||
|
||||
if (list->name == NULL) { /* first one special case */
|
||||
list->name = xstrdup (name);
|
||||
list->value = xstrdup (value);
|
||||
if (NULL == list->name) { /* first one special case */
|
||||
list->name = mystrdup (name);
|
||||
if (NULL == list->name) return -1; /* out of memory */
|
||||
list->value = mystrdup (value);
|
||||
if (NULL == list->value) return -1; /* out of memory */
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (pl = list; pl->next; pl = pl->next) {
|
||||
if (strcmp (pl->name, name) == 0) {
|
||||
if (0 == strcmp (pl->name, name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
xfree (pl->value);
|
||||
pl->value = xstrdup (value);
|
||||
free (pl->value);
|
||||
pl->value = mystrdup (value);
|
||||
if (NULL == pl->value) return -1; /* out of memory */
|
||||
return 1;
|
||||
} else {
|
||||
param_list_t *np = XCALLOC (struct param_list);
|
||||
np->name = xstrdup (name);
|
||||
np->value = xstrdup (value);
|
||||
param_list_t *np = (param_list_t *)mycalloc (sizeof (param_list_t));
|
||||
if (NULL == np) return -1; /* out of memory */
|
||||
np->name = mystrdup (name);
|
||||
if (NULL == np->name) return -1; /* out of memory */
|
||||
np->value = mystrdup (value);
|
||||
if (NULL == np->value) return -1; /* out of memory */
|
||||
pl->next = np;
|
||||
return 0;
|
||||
}
|
||||
@@ -234,7 +161,7 @@ paramListGet (param_list_t *list,
|
||||
assert (name != NULL);
|
||||
|
||||
for (pl = list; pl->next; pl = pl->next) {
|
||||
if (strcmp (pl->name, name) == 0) {
|
||||
if (0 == strcmp (pl->name, name)) {
|
||||
return pl->value;
|
||||
}
|
||||
}
|
||||
@@ -248,11 +175,9 @@ paramListGet (param_list_t *list,
|
||||
string_list_t *
|
||||
stringListInit (const char *value)
|
||||
{
|
||||
string_list_t *np = XCALLOC (struct string_list);
|
||||
string_list_t *np = (string_list_t *)mycalloc (sizeof (string_list_t));
|
||||
if (value)
|
||||
np->value = xstrdup (value); /* This can be NULL */
|
||||
else
|
||||
np->value = NULL;
|
||||
np->value = mystrdup (value); /* This can be NULL */
|
||||
return np;
|
||||
}
|
||||
|
||||
@@ -265,8 +190,8 @@ stringListFree (string_list_t *list)
|
||||
for (pl = list; pl; pl = next) {
|
||||
next = pl->next;
|
||||
if (pl->value)
|
||||
xfree (pl->value);
|
||||
xfree (pl);
|
||||
free (pl->value);
|
||||
free (pl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,31 +205,24 @@ stringListAdd (string_list_t *list,
|
||||
assert (list != NULL);
|
||||
assert (value != NULL);
|
||||
|
||||
if (list->value == NULL) { /* first one special case */
|
||||
list->value = xstrdup (value);
|
||||
if (NULL == list->value) { /* first one special case */
|
||||
list->value = mystrdup (value);
|
||||
if (NULL == list->value) return -1; /* out of memory */
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (pl = list; pl->next; pl = pl->next)
|
||||
; /* skip to end */
|
||||
np = XCALLOC (struct string_list);
|
||||
|
||||
np->value = xstrdup (value);
|
||||
|
||||
np = (string_list_t *)mycalloc (sizeof (string_list_t));
|
||||
if (NULL == np)
|
||||
return -1; /* out of memory */
|
||||
np->value = mystrdup (value);
|
||||
if (NULL == np->value)
|
||||
return -1; /* out of memory */
|
||||
pl->next = np;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_sl(string_list_t *l)
|
||||
{
|
||||
while (l)
|
||||
{
|
||||
fprintf(stderr, "`%s', ", l->value);
|
||||
l = l->next;
|
||||
}
|
||||
fprintf(stderr, "NULL\n");
|
||||
}
|
||||
|
||||
/* return non 0 if whitespace */
|
||||
#define IS_WHITE(c) ((' ' == (c)) || '\t' == (c))
|
||||
#define IS_TERM(c) (('\r' == (c)) || '\n' == (c))
|
||||
@@ -404,13 +322,6 @@ check_hostname_attribute (const char *line)
|
||||
return 0;
|
||||
}
|
||||
|
||||
double
|
||||
d_millitime_atoi(str)
|
||||
char *str;
|
||||
{
|
||||
return (double)millitime_atoi(str);
|
||||
}
|
||||
|
||||
/*
|
||||
Protocol independent parsing
|
||||
*/
|
||||
@@ -421,27 +332,20 @@ cmdParseNameValue (pmail_command_t cmd,
|
||||
{
|
||||
if (strcmp(name, "numloops") == 0)
|
||||
cmd->numLoops = atoi(tok);
|
||||
else if (strcmp(name, "throttle") == 0)
|
||||
cmd->throttle = atoi(tok);
|
||||
else if (strcmp(name, "weight") == 0)
|
||||
cmd->weight = atoi(tok);
|
||||
/* Sean O'Rourke: added startdelay */
|
||||
else if (strcmp(name, "startdelay") == 0)
|
||||
cmd->startDelay = parse_distrib(tok, &d_millitime_atoi);
|
||||
else if (strcmp(name, "idletime") == 0)
|
||||
cmd->idleTime = parse_distrib(tok, &d_millitime_atoi);
|
||||
cmd->idleTime = time_atoi(tok);
|
||||
else if (strcmp(name, "blockid") == 0)
|
||||
cmd->blockID = time_atoi(tok);
|
||||
else if (strcmp(name, "blocktime") == 0)
|
||||
cmd->blockTime = parse_distrib(tok, &d_millitime_atoi);
|
||||
cmd->blockTime = time_atoi(tok);
|
||||
else if (strcmp(name, "loopdelay") == 0)
|
||||
cmd->loopDelay = parse_distrib(tok, &d_millitime_atoi);
|
||||
else if (strcmp(name, "checkmailinterval") == 0)
|
||||
cmd->loopDelay = parse_distrib(tok, &d_millitime_atoi);
|
||||
#ifdef DYNAMIC_THROTTLE
|
||||
else if (strcmp(name, "loopthrottle") == 0)
|
||||
cmd->loopThrottle = millitime_atoi(tok);
|
||||
else if (strcmp(name, "throttlefactor") == 0)
|
||||
cmd->throttleFactor = atof(tok);
|
||||
#endif /* DYNAMIC_THROTTLE */
|
||||
cmd->loopDelay = time_atoi(tok);
|
||||
else if (strcmp(name, "checkmailinterval") == 0) /* BACK COMPAT */
|
||||
cmd->loopDelay = time_atoi(tok);
|
||||
else
|
||||
return 0; /* no match */
|
||||
|
||||
@@ -578,7 +482,6 @@ load_commands(char *commands)
|
||||
int commIndex = 0;
|
||||
int inCommand = 0; /* 0 none, -1 ignore, 1 default, 2 other */
|
||||
string_list_t *param_list = NULL;
|
||||
int i;
|
||||
|
||||
g_default_params = paramListInit (); /* create default section list */
|
||||
|
||||
@@ -588,19 +491,7 @@ load_commands(char *commands)
|
||||
paramListAdd (g_default_params, "numlogins", "1");
|
||||
paramListAdd (g_default_params, "numaddresses", "1");
|
||||
paramListAdd (g_default_params, "weight", "100");
|
||||
#ifdef SOCK_LINESPEED
|
||||
paramListAdd (g_default_params, "latency", "0");
|
||||
paramListAdd (g_default_params, "bandwidth", "0");
|
||||
#endif
|
||||
#ifdef AUTOGEN
|
||||
paramListAdd (g_default_params, "size", "0");
|
||||
paramListAdd (g_default_params, "headers", "5");
|
||||
paramListAdd (g_default_params, "mime", "0");
|
||||
#endif
|
||||
paramListAdd (g_default_params, "throttlefactor", "1.05");
|
||||
|
||||
paramListAdd (g_default_params, "timeout", "60s");
|
||||
|
||||
gn_number_of_commands = count_num_commands(commands);
|
||||
D_PRINTF(stderr, "number_of_commands = %d\n", gn_number_of_commands);
|
||||
if (gn_number_of_commands <= 0) { /* no mail msgs - exit */
|
||||
@@ -609,12 +500,9 @@ load_commands(char *commands)
|
||||
|
||||
/* allocate structure to hold command list (command filename weight) */
|
||||
g_loaded_comm_list =
|
||||
(mail_command_t *) xcalloc(gn_number_of_commands * sizeof(mail_command_t));
|
||||
/* put in "internal" defaults */
|
||||
for (i = 0; i < gn_number_of_commands; i++) {
|
||||
g_loaded_comm_list[i].throttle = 1; /* dynamic throttle rate */
|
||||
}
|
||||
|
||||
(mail_command_t *) mycalloc(gn_number_of_commands
|
||||
* sizeof(mail_command_t));
|
||||
|
||||
while (NULL
|
||||
!= (cmdptr = get_line_from_buffer (cmdptr, line, &lineNumber, 0))) {
|
||||
|
||||
|
||||
@@ -19,9 +19,7 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
# Marcel DePaolis <marcel@netcape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -35,8 +33,6 @@
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _pish_h
|
||||
#define _pish_h
|
||||
/* these are protocol dependent timers for Pop, Imap, Smtp, Http*/
|
||||
typedef struct pish_stats {
|
||||
event_timer_t connect;
|
||||
@@ -69,76 +65,23 @@ typedef struct pish_command {
|
||||
|
||||
char * passwdFormat;
|
||||
|
||||
int net_timeout; /* timeout for network ops */
|
||||
|
||||
long flags; /* protocol specific flags */
|
||||
|
||||
/* SMTP command attrs */
|
||||
char * addressFormat;
|
||||
range_t addressRange; /* address range for all threads */
|
||||
|
||||
int numRecipients; /* recpients per message */
|
||||
char * smtpMailFrom; /* default from address */
|
||||
char * filePattern; /* filename pattern */
|
||||
int fileCount; /* number of files */
|
||||
void * files; /* array of file info */
|
||||
char * filename;
|
||||
dinst_t *numRecipients; /* recpients per message */
|
||||
#ifdef AUTOGEN
|
||||
/* Sean O'Rourke: added auto-generation */
|
||||
dinst_t *genSize; /* message size */
|
||||
dinst_t *genHdrs; /* total number of headers */
|
||||
dinst_t *genMime; /* 0 => text/plain, else N-part MIME */
|
||||
|
||||
enum { /* what to do with checksums */
|
||||
CS_NONE, /* don't do checksums */
|
||||
CS_CHECK, /* report discrepancies */
|
||||
CS_SAVE_BAD /* save messages which fail */
|
||||
} genChecksum;
|
||||
#endif
|
||||
#ifdef SOCK_LINESPEED /* bandwidth-limitation */
|
||||
dinst_t *latency;
|
||||
dinst_t *bandwidth;
|
||||
#endif
|
||||
#ifdef SOCK_SSL /* SSL/TLS support */
|
||||
char *cert;
|
||||
char *key;
|
||||
int useTLS;
|
||||
int sslTunnel;
|
||||
#endif
|
||||
int msgsize; /* message size without trailing CRLF.CRLF */
|
||||
char * msgdata; /* cache the file in mem */
|
||||
|
||||
/* POP/IMAP flag to leave mail on server */
|
||||
dinst_t *leaveMailOnServerDist;
|
||||
|
||||
/* time to read each message */
|
||||
dinst_t *msgReadTime;
|
||||
|
||||
/* Multi-POP vars */
|
||||
double percentActive; /* users concurrently active */
|
||||
dinst_t *userSpacing; /* time alloted for each connection */
|
||||
dinst_t *dropRate; /* fraction of connections dropped */
|
||||
|
||||
/* IMAP command attrs */
|
||||
char * imapSearchFolder;
|
||||
char * imapSearchPattern;
|
||||
int imapSearchRate;
|
||||
|
||||
/* Webmail stuff */
|
||||
char *webBase; /* base for all web url's */
|
||||
string_list_t *webLoginPages; /* sequence of pages after login */
|
||||
/* login format, given to printf(fmt, username, passwd) */
|
||||
char *webLoginFormat;
|
||||
/* format to read message, given to printf(fmt, msgnum) */
|
||||
char *webMsgRead;
|
||||
/* delete format, given to printf(fmt, list_of_msgs) */
|
||||
char *webDeleteFormat;
|
||||
char *webExpunge; /* expunge URL */
|
||||
char *webLogout; /* logout page */
|
||||
char *webIndex; /* index page */
|
||||
} pish_command_t;
|
||||
|
||||
/* TRANSITION functions */
|
||||
extern int pishParseNameValue (pmail_command_t cmd, char *name, char *tok);
|
||||
|
||||
#endif /* _pish_h */
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -39,9 +37,6 @@
|
||||
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
#include "socket.h"
|
||||
#include "xalloc.h"
|
||||
#include "checksum.h"
|
||||
|
||||
typedef struct _doPOP3_state {
|
||||
int numMsgs; /* messages in folder */
|
||||
@@ -49,7 +44,7 @@ typedef struct _doPOP3_state {
|
||||
int msgCounter; /* count in download */
|
||||
} doPOP3_state_t;
|
||||
|
||||
/* flags definitions */
|
||||
/* POP3 flags definitions */
|
||||
#define leaveMailOnServer 0x01
|
||||
|
||||
static void doPop3Exit (ptcx_t ptcx, doPOP3_state_t *me);
|
||||
@@ -65,15 +60,12 @@ PopParseNameValue (pmail_command_t cmd,
|
||||
/* find a home for the attr/value */
|
||||
if (pishParseNameValue(cmd, name, tok) == 0)
|
||||
; /* done */
|
||||
else if (strcmp(name, "leavemailonserver") == 0) {
|
||||
else if (strcmp(name, "leavemailonserver") == 0)
|
||||
if (atoi(tok) > 0) {
|
||||
pish->flags |= leaveMailOnServer;
|
||||
pish->leaveMailOnServerDist =
|
||||
parse_distrib(tok, (value_parser_t)&atof);
|
||||
} else {
|
||||
pish->flags &= ~leaveMailOnServer;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
@@ -90,7 +82,8 @@ Pop3ParseStart (pmail_command_t cmd,
|
||||
param_list_t *defparm)
|
||||
{
|
||||
param_list_t *pp;
|
||||
pish_command_t *pish = XCALLOC(pish_command_t);
|
||||
pish_command_t *pish = (pish_command_t *)mycalloc
|
||||
(sizeof (pish_command_t));
|
||||
cmd->data = pish;
|
||||
|
||||
cmd->numLoops = 9999; /* default 9999 downloads */
|
||||
@@ -179,12 +172,7 @@ doPopCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, in
|
||||
T_PRINTF(ptcx->logfile, command, strlen (command), "POP3 SendCommand");
|
||||
rc = doCommandResponse(ptcx, sock, command, response, resplen);
|
||||
if (rc == -1)
|
||||
{
|
||||
trimEndWhite (command);
|
||||
trimEndWhite (response);
|
||||
returnerr(debugfile,"POP3 error command=[%s], response=[%s]\n",
|
||||
command, response);
|
||||
}
|
||||
return rc;
|
||||
T_PRINTF(ptcx->logfile, response, strlen(response),
|
||||
"POP3 ReadResponse"); /* telemetry log. should be lower level */
|
||||
/* D_PRINTF(stderr, "POP command=[%s] response=[%s]\n", command, response); */
|
||||
@@ -255,7 +243,7 @@ popLogin(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock)
|
||||
void *
|
||||
doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
{
|
||||
doPOP3_state_t *me = XCALLOC (doPOP3_state_t);
|
||||
doPOP3_state_t *me = (doPOP3_state_t *)mycalloc (sizeof (doPOP3_state_t));
|
||||
char respBuffer[MAX_RESPONSE_LEN];
|
||||
int rc;
|
||||
int numBytes;
|
||||
@@ -268,9 +256,7 @@ doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
me->numMsgs = 0;
|
||||
me->totalMsgLength = 0;
|
||||
me->msgCounter = 0;
|
||||
|
||||
ptcx->net_timeout = pish->net_timeout;
|
||||
|
||||
|
||||
event_start(ptcx, &stats->connect);
|
||||
ptcx->sock = connectSocket(ptcx, &pish->hostInfo, "tcp");
|
||||
event_stop(ptcx, &stats->connect);
|
||||
@@ -280,7 +266,7 @@ doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
returnerr(debugfile, "POP3 Couldn't connect to %s: %s\n",
|
||||
pish->hostInfo.hostName, neterrstr());
|
||||
}
|
||||
xfree (me);
|
||||
myfree (me);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -290,13 +276,6 @@ doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
if (pish->sslTunnel)
|
||||
SSL_INIT(ptcx->sock, pish);
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
LS_INIT(ptcx->sock, pish);
|
||||
|
||||
/* READ connect response from server */
|
||||
event_start(ptcx, &stats->banner);
|
||||
numBytes = readResponse(ptcx, ptcx->sock, respBuffer, sizeof(respBuffer));
|
||||
@@ -311,43 +290,6 @@ doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
|
||||
if (!pish->useTLS)
|
||||
goto end_tls;
|
||||
/*
|
||||
** Try TLS
|
||||
*/
|
||||
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doPopCommandResponse(ptcx, ptcx->sock, "CAPA" CRLF, respBuffer,
|
||||
sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
stats->cmd.errs++;
|
||||
goto end_tls;
|
||||
}
|
||||
if (strstr(respBuffer, "STLS") != NULL) {
|
||||
SOCKET s = BADSOCKET_VALUE;
|
||||
D_PRINTF(debugfile, "trying STLS\n");
|
||||
event_start(ptcx, &stats->cmd);
|
||||
if (doPopCommandResponse(ptcx, ptcx->sock, "STLS" CRLF, respBuffer,
|
||||
sizeof(respBuffer) >= 0)) {
|
||||
s = ptcx->sock;
|
||||
SSL_INIT(s, pish);
|
||||
}
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (BADSOCKET(s)) {
|
||||
D_PRINTF(stderr, "STLS failed\n");
|
||||
stats->cmd.errs++;
|
||||
} else {
|
||||
ptcx->sock = s;
|
||||
}
|
||||
}
|
||||
end_tls:
|
||||
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
/*
|
||||
* LOGIN
|
||||
*/
|
||||
@@ -357,20 +299,7 @@ doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
doPop3Exit (ptcx, me);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef POP_UIDL
|
||||
/* send an UIDL */
|
||||
sprintf(command, "UIDL" CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doPopCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->cmd.errs++;
|
||||
}
|
||||
doPop3Exit (ptcx, me);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* POP_UIDL */
|
||||
|
||||
/* send a STAT */
|
||||
sprintf(command, "STAT%s", CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
@@ -409,7 +338,6 @@ doPop3Loop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
||||
int rc, numBytes;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
int leave_on_server;
|
||||
|
||||
if (me->msgCounter >= me->numMsgs) return -1; /* done, close */
|
||||
|
||||
@@ -430,14 +358,10 @@ doPop3Loop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
||||
}
|
||||
|
||||
/* read msg */
|
||||
if (pish->genChecksum == CS_NONE)
|
||||
numBytes = retrMsg(ptcx, ptcx->sock);
|
||||
else
|
||||
numBytes = cs_retrieve(ptcx, ptcx->sock, CRLF CRLF, CRLF "." CRLF);
|
||||
|
||||
numBytes = retrMsg(ptcx, NULL, 0 , ptcx->sock);
|
||||
event_stop(ptcx, &stats->msgread);
|
||||
|
||||
if (numBytes < 0) {
|
||||
if (numBytes <= 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->msgread.errs++;
|
||||
returnerr(debugfile,"POP3 Error retrieving msg %d: %s\n",
|
||||
@@ -447,10 +371,8 @@ doPop3Loop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if we're not told to leave mail on server, delete the message */
|
||||
leave_on_server = (int)sample(pish->leaveMailOnServerDist);
|
||||
if (!(pish->flags & leaveMailOnServer) ||
|
||||
(leave_on_server == 0)) {
|
||||
/* if we're not told to leave mail on server, delete the message */
|
||||
if (!(pish->flags & leaveMailOnServer)) {
|
||||
/* send the DELE command */
|
||||
sprintf(command, "DELE %d%s", me->msgCounter, CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
@@ -499,5 +421,5 @@ doPop3Exit (ptcx_t ptcx, doPOP3_state_t *me)
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
|
||||
xfree (me);
|
||||
myfree (me);
|
||||
}
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#include "sb.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static int _sb_refill(ptcx_t, socket_buffer *);
|
||||
static void _sb_consume(socket_buffer *, int );
|
||||
|
||||
socket_buffer *
|
||||
sb_new(sock, len)
|
||||
SOCKET sock;
|
||||
int len;
|
||||
{
|
||||
socket_buffer *sb = xalloc(sizeof(socket_buffer) + len);
|
||||
sb->buf[len] = '\0';
|
||||
sb->len = len;
|
||||
sb->data = 0;
|
||||
sb->sock = sock;
|
||||
sb->eof = 0;
|
||||
return sb;
|
||||
}
|
||||
|
||||
void
|
||||
sb_delete(sb)
|
||||
socket_buffer *sb;
|
||||
{
|
||||
if (!BADSOCKET(sb->sock))
|
||||
NETCLOSE(sb->sock);
|
||||
xfree(sb);
|
||||
}
|
||||
|
||||
static int
|
||||
_sb_refill(ptcx, sb)
|
||||
ptcx_t ptcx;
|
||||
socket_buffer *sb;
|
||||
{
|
||||
int len;
|
||||
if (sb->eof)
|
||||
return -1;
|
||||
len = retryRead(ptcx, sb->sock, sb->buf + sb->data,
|
||||
sb->len - sb->data);
|
||||
if (len <= 0)
|
||||
{
|
||||
D_PRINTF(debugfile, "_sb_refill: retryRead failed: %s\n",
|
||||
strerror(errno));
|
||||
sb->eof = 1;
|
||||
return -1;
|
||||
}
|
||||
sb->data += len;
|
||||
ptcx->bytesread += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
_sb_consume(sb, len)
|
||||
socket_buffer *sb;
|
||||
int len;
|
||||
{
|
||||
assert (len <= sb->data);
|
||||
sb->data -= len;
|
||||
if (sb->data > 0)
|
||||
memmove(sb->buf, sb->buf + len, sb->data);
|
||||
}
|
||||
|
||||
int
|
||||
sb_discard(ptcx, sb, pat)
|
||||
ptcx_t ptcx;
|
||||
socket_buffer *sb;
|
||||
char *pat;
|
||||
{
|
||||
int patlen = strlen(pat);
|
||||
char *ptr;
|
||||
for (;;)
|
||||
{
|
||||
if (sb->data < patlen)
|
||||
{
|
||||
if (_sb_refill(ptcx, sb) < 0)
|
||||
{
|
||||
/* EOF */
|
||||
_sb_consume(sb, sb->data);
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
sb->buf[sb->data] = '\0';
|
||||
if ((ptr = strstr(sb->buf, pat)) != NULL)
|
||||
{
|
||||
ptr += patlen; /* discard delimiter as well */
|
||||
_sb_consume(sb, (ptr - sb->buf));
|
||||
return 0;
|
||||
}
|
||||
_sb_consume(sb, sb->data - (patlen - 1));
|
||||
}
|
||||
/* notreached */
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
sb_discardn(ptcx, sb, n)
|
||||
ptcx_t ptcx;
|
||||
socket_buffer *sb;
|
||||
int n;
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (n < sb->data)
|
||||
{
|
||||
_sb_consume(sb, n);
|
||||
return;
|
||||
}
|
||||
n -= sb->data;
|
||||
_sb_consume(sb, sb->data);
|
||||
if (_sb_refill(ptcx, sb) < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sb_get(ptcx, sb, pat)
|
||||
ptcx_t ptcx;
|
||||
socket_buffer *sb;
|
||||
char *pat;
|
||||
{
|
||||
int patlen = strlen(pat);
|
||||
int offset = 0;
|
||||
char *ptr;
|
||||
for (;;)
|
||||
{
|
||||
while (sb->data < sb->len && sb->data - offset < patlen)
|
||||
if (_sb_refill(ptcx, sb) < 0)
|
||||
return -1;
|
||||
if (sb->data == sb->len)
|
||||
return sb->len;
|
||||
if ((ptr = strstr(sb->buf + offset, pat)) != NULL)
|
||||
return (ptr - sb->buf);
|
||||
offset = sb->data - (patlen - 1);
|
||||
}
|
||||
/* notreached */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
sb_read(ptcx, sb)
|
||||
ptcx_t ptcx;
|
||||
socket_buffer *sb;
|
||||
{
|
||||
int ret;
|
||||
if (sb->data == 0)
|
||||
_sb_refill(ptcx, sb);
|
||||
ret = sb->data;
|
||||
_sb_consume(sb, sb->data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _sb_h
|
||||
#define _sb_h
|
||||
|
||||
#include "socket.h"
|
||||
#include "xalloc.h"
|
||||
#include "bench.h"
|
||||
|
||||
/* sb -- poor man's STDIO */
|
||||
|
||||
/*
|
||||
** SOCKET_BUFFER -- buffered sockets to make parsing easier.
|
||||
*/
|
||||
|
||||
typedef struct socket_buffer {
|
||||
int data; /* data in buffer */
|
||||
int len; /* length of buffer */
|
||||
SOCKET sock; /* underlying socket */
|
||||
int eof; /* have we seen eof? */
|
||||
char buf[1]; /* actually len + 1 bytes */
|
||||
} socket_buffer;
|
||||
|
||||
socket_buffer * sb_new(SOCKET, int);
|
||||
void sb_delete(socket_buffer *);
|
||||
int sb_discard(ptcx_t, socket_buffer *, char *);
|
||||
void sb_discardn(ptcx_t, socket_buffer *, int);
|
||||
int sb_get(ptcx_t ptcx, socket_buffer *, char *);
|
||||
|
||||
int sb_read(ptcx_t ptcx, socket_buffer *sb);
|
||||
|
||||
#endif /* _sb_h */
|
||||
@@ -21,8 +21,6 @@
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -37,11 +35,8 @@
|
||||
*/
|
||||
/* SMTP protocol tests */
|
||||
|
||||
#include <ctype.h>
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
#include "generate.h"
|
||||
#include "xalloc.h"
|
||||
#include <glob.h> /* for glob, globfree */
|
||||
|
||||
#define MAXCOMMANDLEN 256 /* parse buffer length */
|
||||
@@ -65,7 +60,6 @@ typedef struct {
|
||||
#define useEHLO 0x01 /* use EHLO instead of HELO */
|
||||
#define useAUTHLOGIN 0x02 /* use AUTH LOGIN to authenticate */
|
||||
#define useAUTHPLAIN 0x04 /* use AUTH PLAIN to authenticate */
|
||||
#define useLMTP 0x08 /* use LMTP instead of SMTP */
|
||||
|
||||
static void doSMTPExit (ptcx_t ptcx, doSMTP_state_t *me);
|
||||
|
||||
@@ -108,7 +102,7 @@ SmtpFileInit (pmail_command_t cmd, /* command being checked */
|
||||
/* We don't really need much of the file, but it warms up the
|
||||
* cache. Limit at 1Mb */
|
||||
msgsize = MIN (statbuf.st_size, 1024*1024);
|
||||
msgdata = (char *) xcalloc(msgsize+strlen(MSG_TRAILER)+1);
|
||||
msgdata = (char *) mycalloc(msgsize+strlen(MSG_TRAILER)+1);
|
||||
|
||||
if ((bytesRead = read(fd, msgdata, msgsize)) <= 0) {
|
||||
close(fd);
|
||||
@@ -142,7 +136,7 @@ SmtpFileInit (pmail_command_t cmd, /* command being checked */
|
||||
cp += strlen(PROTO_MAIL_FROM);
|
||||
cp2 = strchr(cp, '\n');
|
||||
off = cp2 - cp;
|
||||
fileEntry->msgMailFrom = (char *) xcalloc(off+1);
|
||||
fileEntry->msgMailFrom = (char *) mycalloc(off+1);
|
||||
memcpy(fileEntry->msgMailFrom, cp, off);
|
||||
fileEntry->msgMailFrom[off] = 0;
|
||||
D_PRINTF(stderr, "got PROTO_MAIL_FROM:%s\n",
|
||||
@@ -163,7 +157,7 @@ SmtpFileInit (pmail_command_t cmd, /* command being checked */
|
||||
}
|
||||
|
||||
|
||||
xfree (msgdata);
|
||||
myfree (msgdata);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -190,10 +184,10 @@ SmtpFilePrep (pmail_command_t cmd, /* command being checked */
|
||||
pish->fileCount = globs.gl_pathc;
|
||||
D_PRINTF (stderr, "SmtpFilePrep: filePattern='%s' entries=%d\n",
|
||||
pish->filePattern, pish->fileCount);
|
||||
pish->files = xcalloc (pish->fileCount * sizeof (smtp_file_t));
|
||||
pish->files = mycalloc (pish->fileCount * sizeof (smtp_file_t));
|
||||
fileEntry = pish->files;
|
||||
for (ii = 0; ii < pish->fileCount; ++ii, ++fileEntry) {
|
||||
fileEntry->filename = xstrdup (globs.gl_pathv[ii]);
|
||||
fileEntry->filename = mystrdup (globs.gl_pathv[ii]);
|
||||
if (SmtpFileInit (cmd, defparm, fileEntry) < 0) {
|
||||
globfree (&globs);
|
||||
return -1;
|
||||
@@ -366,7 +360,8 @@ SmtpParseStart (pmail_command_t cmd,
|
||||
param_list_t *defparm)
|
||||
{
|
||||
param_list_t *pp;
|
||||
pish_command_t *pish = XCALLOC(pish_command_t);
|
||||
pish_command_t *pish = (pish_command_t *)mycalloc
|
||||
(sizeof (pish_command_t));
|
||||
cmd->data = pish;
|
||||
|
||||
cmd->numLoops = 1; /* default 1 message */
|
||||
@@ -374,8 +369,9 @@ SmtpParseStart (pmail_command_t cmd,
|
||||
|
||||
D_PRINTF(stderr, "Smtp Assign defaults\n");
|
||||
/* Fill in defaults first, ignore defaults we dont use */
|
||||
for (pp = defparm; pp; pp = pp->next)
|
||||
for (pp = defparm; pp; pp = pp->next) {
|
||||
(void)pishParseNameValue (cmd, pp->name, pp->value);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -389,9 +385,6 @@ SmtpParseEnd (pmail_command_t cmd,
|
||||
param_list_t *defparm)
|
||||
{
|
||||
string_list_t *sp;
|
||||
int fd;
|
||||
int bytesRead;
|
||||
struct stat statbuf;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
|
||||
/* Now parse section lines */
|
||||
@@ -420,8 +413,8 @@ SmtpParseEnd (pmail_command_t cmd,
|
||||
}
|
||||
|
||||
if (!pish->loginFormat) {
|
||||
D_PRINTF(stderr,"missing loginFormat for SMTP");
|
||||
return returnerr(stderr,"missing loginFormat for SMTP\n");
|
||||
D_PRINTF(stderr,"missing loginFormat for command");
|
||||
return returnerr(stderr,"missing loginFormat for command\n");
|
||||
}
|
||||
|
||||
if (!pish->passwdFormat) {
|
||||
@@ -436,53 +429,8 @@ SmtpParseEnd (pmail_command_t cmd,
|
||||
|
||||
/* check for required attrs */
|
||||
if (!pish->filePattern) {
|
||||
D_PRINTF(stderr,"missing file/generator for SMTP command");
|
||||
return returnerr(stderr,"missing file/generator for SMTP command\n");
|
||||
}
|
||||
|
||||
#ifdef AUTOGEN
|
||||
if(strcmp(pish->filePattern, "auto") == 0) {
|
||||
/* automatically generate messages */
|
||||
pish->filePattern = NULL;
|
||||
gen_init();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* read the contents of file into struct */
|
||||
memset(&statbuf, 0, sizeof(statbuf));
|
||||
if (stat(pish->filename, &statbuf) != 0) {
|
||||
return returnerr(stderr,"Couldn't stat file %s: errno=%d: %s\n",
|
||||
pish->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
/* open file */
|
||||
if ((fd = open(pish->filename, O_RDONLY)) <= 0) {
|
||||
return returnerr(stderr, "Cannot open file %s: errno=%d: %s\n",
|
||||
pish->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
/* read into loaded_comm_list */
|
||||
pish->msgsize = statbuf.st_size;
|
||||
pish->msgdata = (char *) xcalloc(pish->msgsize+strlen(MSG_TRAILER)+1);
|
||||
|
||||
if ((bytesRead = read(fd, pish->msgdata, pish->msgsize)) <= 0) {
|
||||
close(fd);
|
||||
return returnerr(stderr, "Cannot read file %s: errno=%d: %s\n",
|
||||
pish->filename, errno, strerror(errno));
|
||||
}
|
||||
|
||||
if (bytesRead != pish->msgsize) {
|
||||
returnerr(stderr, "Error reading file %s, got %d expected %d\n",
|
||||
pish->filename, bytesRead, pish->msgsize);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pish->msgdata[pish->msgsize] = 0;
|
||||
|
||||
strcat(pish->msgdata, MSG_TRAILER);
|
||||
|
||||
close(fd);
|
||||
D_PRINTF(stderr,"missing file for SMTP command");
|
||||
return returnerr(stderr,"missing file for SMTP command\n");
|
||||
}
|
||||
|
||||
SmtpFilePrep (cmd, defparm);
|
||||
@@ -508,8 +456,6 @@ SmtpParseEnd (pmail_command_t cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern double d_millitime_atoi(char*);
|
||||
|
||||
/* ======================================================================
|
||||
These routine will become protcol specific.
|
||||
Since SMTP is the most complex, they are here for now.
|
||||
@@ -519,7 +465,6 @@ extern double d_millitime_atoi(char*);
|
||||
TRANSITION: handles all the old names-fields for POP, IMAP, SMTP, HTTP
|
||||
This goes away when commands have protocol extensible fields
|
||||
*/
|
||||
|
||||
int
|
||||
pishParseNameValue (pmail_command_t cmd,
|
||||
char *name,
|
||||
@@ -532,13 +477,13 @@ pishParseNameValue (pmail_command_t cmd,
|
||||
if (cmdParseNameValue(cmd, name, tok))
|
||||
; /* done */
|
||||
else if (strcmp(name, "server") == 0)
|
||||
pish->hostInfo.hostName = xstrdup (tok);
|
||||
pish->hostInfo.hostName = mystrdup (tok);
|
||||
else if (strcmp(name, "smtpmailfrom") == 0)
|
||||
pish->smtpMailFrom = xstrdup (tok);
|
||||
pish->smtpMailFrom = mystrdup (tok);
|
||||
else if (strcmp(name, "loginformat") == 0)
|
||||
pish->loginFormat = xstrdup (tok);
|
||||
pish->loginFormat = mystrdup (tok);
|
||||
else if (strcmp(name, "addressformat") == 0)
|
||||
pish->addressFormat = xstrdup (tok);
|
||||
pish->addressFormat = mystrdup (tok);
|
||||
else if (strcmp(name, "firstlogin") == 0)
|
||||
pish->loginRange.first = atoi(tok);
|
||||
else if (strcmp(name, "numlogins") == 0)
|
||||
@@ -559,43 +504,25 @@ pishParseNameValue (pmail_command_t cmd,
|
||||
pish->addressRange.sequential = atoi(tok);
|
||||
else if (strcmp(name, "portnum") == 0)
|
||||
pish->hostInfo.portNum = atoi(tok);
|
||||
else if ((strcmp(name, "numrecips") == 0)
|
||||
|| (strcmp(name, "numrecipients") == 0))
|
||||
pish->numRecipients = parse_distrib(tok, (value_parser_t)&atof);
|
||||
else if (strcmp(name, "numrecips") == 0)
|
||||
pish->numRecipients = atoi(tok);
|
||||
else if (strcmp(name, "numrecipients") == 0)
|
||||
pish->numRecipients = atoi(tok);
|
||||
else if (strcmp(name, "file") == 0)
|
||||
pish->filename = xstrdup (tok);
|
||||
|
||||
/* Sean O'Rourke: parse Multi-pop attr's */
|
||||
else if(strcmp(name, "percentactive") == 0)
|
||||
pish->percentActive = atof(tok)/100.0;
|
||||
else if(strcmp(name, "userspacing") == 0)
|
||||
pish->userSpacing
|
||||
= parse_distrib(tok, (value_parser_t)&d_millitime_atoi);
|
||||
else if (strcmp(name, "droprate") == 0)
|
||||
pish->dropRate = parse_distrib(tok, (value_parser_t)&atof);
|
||||
else if (strcmp(name, "msgreadtime") == 0)
|
||||
pish->msgReadTime
|
||||
= parse_distrib(tok, (value_parser_t)&d_millitime_atoi);
|
||||
pish->filePattern = mystrdup (tok);
|
||||
else if (strcmp(name, "passwdformat") == 0)
|
||||
pish->passwdFormat = xstrdup (tok);
|
||||
pish->passwdFormat = mystrdup (tok);
|
||||
else if (strcmp(name, "searchfolder") == 0)
|
||||
pish->imapSearchFolder = xstrdup (tok);
|
||||
pish->imapSearchFolder = mystrdup (tok);
|
||||
else if (strcmp(name, "searchpattern") == 0)
|
||||
pish->imapSearchPattern = xstrdup (tok);
|
||||
pish->imapSearchPattern = mystrdup (tok);
|
||||
else if (strcmp(name, "searchrate") == 0)
|
||||
pish->imapSearchRate = atoi(tok);
|
||||
else if (strcmp(name, "timeout") == 0)
|
||||
pish->net_timeout = millitime_atoi(tok);
|
||||
else if (strcmp(name, "useehlo") == 0)
|
||||
if (atoi(tok) == 1) {
|
||||
if (atoi(tok)) {
|
||||
pish->flags |= useEHLO;
|
||||
pish->flags &= ~useLMTP;
|
||||
}
|
||||
else if (atoi(tok) == 2) {
|
||||
pish->flags |= useLMTP;
|
||||
} else {
|
||||
pish->flags &= ~useEHLO;
|
||||
pish->flags &= ~useLMTP;
|
||||
}
|
||||
else if (strcmp(name, "useauthlogin") == 0)
|
||||
if (atoi(tok) > 0) {
|
||||
@@ -609,54 +536,6 @@ pishParseNameValue (pmail_command_t cmd,
|
||||
} else {
|
||||
pish->flags &= ~useAUTHPLAIN;
|
||||
}
|
||||
|
||||
#ifdef AUTOGEN
|
||||
/* Sean O'Rourke: added auto-generated messages */
|
||||
else if (strcmp(name, "size") == 0)
|
||||
pish->genSize = parse_distrib(tok, (value_parser_t)&size_atof);
|
||||
else if (strcmp(name, "headers") == 0)
|
||||
pish->genHdrs = parse_distrib(tok, (value_parser_t)&atof);
|
||||
else if (strcmp(name, "mime") == 0)
|
||||
pish->genMime = parse_distrib(tok, (value_parser_t)&atof);
|
||||
# ifdef GEN_CHECKSUM
|
||||
else if (strcmp(name, "checksum") == 0) {
|
||||
if (tolower(*tok) == 'n')
|
||||
pish->genChecksum = CS_NONE;
|
||||
else if (tolower(*tok) == 'y' || atoi(tok) != 0) {
|
||||
fprintf(stderr, "Generating checksums.\n");
|
||||
pish->genChecksum = CS_CHECK;
|
||||
} else if (tolower(*tok) == 's')
|
||||
pish->genChecksum = CS_SAVE_BAD;
|
||||
else {
|
||||
fprintf(stderr, "Unrecognized checksum option `%s'\n", tok);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
# else /* GEN_CHECKSUM */
|
||||
pish->genChecksum = CS_NONE;
|
||||
# endif /* GEN_CHECKSUM */
|
||||
#endif /* AUTOGEN */
|
||||
#ifdef SOCK_LINESPEED
|
||||
else if (strcmp(name, "latency") == 0)
|
||||
pish->latency = parse_distrib(tok, &d_millitime_atoi);
|
||||
else if (strcmp(name, "bandwidth") == 0)
|
||||
pish->bandwidth = parse_distrib(tok, (value_parser_t)&size_atof);
|
||||
#endif /* SOCK_LINESPEED */
|
||||
#ifdef SOCK_SSL
|
||||
else if (strcmp(name, "sslcert") == 0)
|
||||
pish->cert = xstrdup(tok);
|
||||
else if (strcmp(name, "sslkey") == 0)
|
||||
pish->key = xstrdup(tok);
|
||||
/* NOTE: starttls and ssltunnel are mutually exclusive */
|
||||
else if (strcmp(name, "starttls") == 0) {
|
||||
if ((pish->useTLS = atoi(tok)))
|
||||
pish->sslTunnel = 0;
|
||||
} else if (strcmp(name, "ssltunnel") == 0) {
|
||||
if ((pish->sslTunnel = atoi(tok)))
|
||||
pish->useTLS = 0;
|
||||
}
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
@@ -670,7 +549,7 @@ pishStatsInit(mail_command_t *cmd, cmd_stats_t *p, int procNum, int threadNum)
|
||||
assert (NULL != p);
|
||||
|
||||
if (!p->data) { /* create it */
|
||||
p->data = XCALLOC (pish_stats_t);
|
||||
p->data = mycalloc (sizeof (pish_stats_t));
|
||||
} else { /* zero it */
|
||||
memset (p->data, 0, sizeof (pish_stats_t));
|
||||
}
|
||||
@@ -827,60 +706,27 @@ isSmtpResponseOK(char * s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
isSmtpResponse(char *s)
|
||||
{
|
||||
return(isdigit(s[0]) && isdigit(s[1]) && isdigit(s[2]) && (s[3] == ' '));
|
||||
}
|
||||
|
||||
/*
|
||||
** Sean O'Rourke: changed this to ignore SMTP debugging output. also changed
|
||||
** to differentiate between I/O errors and 4xx/5xx codes.
|
||||
**
|
||||
** Returns:
|
||||
** 0 -- no error, 2xx/3xx status code
|
||||
** -1 -- I/O error
|
||||
** -2 -- 4xx/5xx status code
|
||||
*/
|
||||
|
||||
int
|
||||
doSmtpCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen)
|
||||
{
|
||||
int rc;
|
||||
|
||||
T_PRINTF(ptcx->logfile, command, strlen (command), "SMTP SendCommand");
|
||||
/* rc = doCommandResponse(ptcx, sock, command, response, resplen); */
|
||||
if ((rc = sendCommand(ptcx, sock, command)) == -1) {
|
||||
strcat (ptcx->errMsg, "<doCommandResponse");
|
||||
rc = doCommandResponse(ptcx, sock, command, response, resplen);
|
||||
if (rc == -1)
|
||||
return rc;
|
||||
T_PRINTF(ptcx->logfile, response, strlen(response),
|
||||
"SMTP ReadResponse"); /* telemetry log. should be lower level */
|
||||
/* D_PRINTF(stderr, "SMTP command=[%s] response=[%s]\n", command, response); */
|
||||
if (!isSmtpResponseOK(response)) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
/* dont modify command (in case it could be re-tried) */
|
||||
trimEndWhite (response); /* clean up for printing */
|
||||
strcpy (ptcx->errMsg, "SmtpCommandResponse: got SMTP error response");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
/* read server response line */
|
||||
if ((rc = readResponse(ptcx, sock, response, resplen)) <= 0) {
|
||||
strcat (ptcx->errMsg, "<doCommandResponse");
|
||||
return -1;
|
||||
}
|
||||
|
||||
T_PRINTF(ptcx->logfile, response, strlen(response),
|
||||
"SMTP ReadResponse"); /* telemetry log. should be lower level */
|
||||
/* D_PRINTF(stderr, "SMTP command=[%s] response=[%s]\n", command, response); */
|
||||
if (isSmtpResponse(response)) {
|
||||
if(!isSmtpResponseOK(response)) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
/* dont modify command (in case it could be re-tried) */
|
||||
trimEndWhite (response); /* clean up for printing */
|
||||
strcpy (ptcx->errMsg,
|
||||
"SmtpCommandResponse: got SMTP error response");
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1; /* invalid response. */
|
||||
}
|
||||
/* not reached */
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char basis_64[] =
|
||||
@@ -964,13 +810,13 @@ smtpAuthPlain(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->login.errs++;
|
||||
strcat (ptcx->errMsg, "<SmtpLogin: failure sending AUTH PLAIN");
|
||||
trimEndWhite (command);
|
||||
returnerr(debugfile, "%s command=[%.99s] response=[%.99s]\n", /* ??? */
|
||||
PSTR(ptcx->errMsg), command, respBuffer);
|
||||
ptcx->errMsg, command, respBuffer);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -992,7 +838,7 @@ smtpAuthPlain(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock
|
||||
if (str_to_base64(auth_msg, auth_msg_len, base64_buf, sizeof(base64_buf)) == -1) {
|
||||
stats->login.errs++;
|
||||
strcpy (ptcx->errMsg, "SmtpLogin: Internal error encoding user");
|
||||
returnerr(debugfile, "%s [%.199s]\n", PSTR(ptcx->errMsg), mailUser); /* ??? */
|
||||
returnerr(debugfile, "%s [%.199s]\n", ptcx->errMsg, mailUser); /* ??? */
|
||||
return -1;
|
||||
}
|
||||
sprintf(command, "%s%s", base64_buf, CRLF);
|
||||
@@ -1000,11 +846,11 @@ smtpAuthPlain(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock
|
||||
event_start(ptcx, &stats->login);
|
||||
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->login);
|
||||
if (rc < 0) {
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->login.errs++;
|
||||
strcat (ptcx->errMsg, "<SmtpLogin: failure sending auth message");
|
||||
returnerr(debugfile,"%s [%.199s]\n", PSTR(ptcx->errMsg), mailUser); /* ??? */
|
||||
returnerr(debugfile,"%s [%.199s]\n", ptcx->errMsg, mailUser); /* ??? */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1044,7 +890,7 @@ smtpAuthLogin(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->login.errs++;
|
||||
strcat (ptcx->errMsg, "<SmtpLogin: failure sending AUTH LOGIN");
|
||||
@@ -1069,7 +915,7 @@ smtpAuthLogin(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->login.errs++;
|
||||
strcat (ptcx->errMsg, "<SmtpLogin: failure sending user");
|
||||
@@ -1092,7 +938,7 @@ smtpAuthLogin(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock
|
||||
event_start(ptcx, &stats->login);
|
||||
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->login);
|
||||
if (rc < 0) {
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->login.errs++;
|
||||
strcat (ptcx->errMsg, "<SmtpLogin: failure sending password");
|
||||
@@ -1107,55 +953,20 @@ smtpAuthLogin(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
|
||||
static SOCKET
|
||||
starttls(ptcx_t ptcx, mail_command_t *cmd, SOCKET sock)
|
||||
{
|
||||
char resp[MAX_RESPONSE_LEN];
|
||||
|
||||
int ret = doSmtpCommandResponse(ptcx, sock, "STARTTLS" CRLF,
|
||||
resp, sizeof(resp));
|
||||
switch (ret)
|
||||
{
|
||||
case -2:
|
||||
returnerr(debugfile, "STARTTLS: %.99s\n", resp);
|
||||
return sock;
|
||||
case -1:
|
||||
returnerr(debugfile, "STARTTLS: %.99s\n", resp);
|
||||
return BADSOCKET_VALUE;
|
||||
case 0:
|
||||
/* Initialize SSL */
|
||||
SSL_INIT(sock, (pish_command_t*)cmd->data);
|
||||
return sock;
|
||||
};
|
||||
/* not reached */
|
||||
return BADSOCKET_VALUE;
|
||||
}
|
||||
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
/* Entry point for running tests */
|
||||
void *
|
||||
sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
{
|
||||
doSMTP_state_t *me = XCALLOC (doSMTP_state_t);
|
||||
doSMTP_state_t *me = (doSMTP_state_t *)mycalloc (sizeof (doSMTP_state_t));
|
||||
char respBuffer[MAX_RESPONSE_LEN];
|
||||
char command[MAX_COMMAND_LEN];
|
||||
char command[MAXCOMMANDLEN];
|
||||
int numBytes;
|
||||
int rc;
|
||||
pish_command_t *pish;
|
||||
pish_stats_t *stats;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
|
||||
assert(ptcx != NULL);
|
||||
assert(cmd != NULL);
|
||||
assert(ptimer != NULL);
|
||||
assert(cmd->data != NULL);
|
||||
assert(ptimer->data != NULL);
|
||||
if (!me) return NULL;
|
||||
|
||||
pish = (pish_command_t *)cmd->data;
|
||||
stats = (pish_stats_t *)ptimer->data;
|
||||
ptcx->net_timeout = pish->net_timeout;
|
||||
|
||||
event_start(ptcx, &stats->connect);
|
||||
ptcx->sock = connectSocket(ptcx, &pish->hostInfo, "tcp");
|
||||
@@ -1166,7 +977,7 @@ sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
returnerr(debugfile, "%s SMTP Couldn't connect to %s: %s\n",
|
||||
ptcx->errMsg, pish->hostInfo.hostName, neterrstr());
|
||||
}
|
||||
xfree (me);
|
||||
myfree (me);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1176,141 +987,50 @@ sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
if (pish->sslTunnel)
|
||||
SSL_INIT(ptcx->sock, pish);
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
LS_INIT(ptcx->sock, pish);
|
||||
|
||||
/* READ connect response from server */
|
||||
event_start(ptcx, &stats->banner);
|
||||
/* Sean O'Rourke: change to handle milter debugging stuff. */
|
||||
for(;;) {
|
||||
/* read server response line */
|
||||
numBytes = readResponse(ptcx,
|
||||
ptcx->sock,
|
||||
respBuffer,
|
||||
sizeof(respBuffer));
|
||||
if (numBytes <= 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->banner.errs++;
|
||||
returnerr(debugfile,"%s SMTP Error reading banner: %s\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
}
|
||||
event_stop(ptcx, &stats->banner);
|
||||
doSMTPExit (ptcx, me);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (isSmtpResponse(respBuffer)) {
|
||||
event_stop(ptcx, &stats->banner);
|
||||
if (isSmtpResponseOK(respBuffer) == 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->banner.errs++;
|
||||
returnerr(debugfile, "%s Got SMTP ERROR response [%.99s]\n",
|
||||
ptcx->errMsg, respBuffer);
|
||||
}
|
||||
doSMTPExit (ptcx, me);
|
||||
return NULL;
|
||||
}
|
||||
D_PRINTF(debugfile,"read connect response\n");
|
||||
break;
|
||||
}
|
||||
numBytes = readResponse(ptcx, ptcx->sock, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->banner);
|
||||
if (numBytes <= 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->banner.errs++;
|
||||
returnerr(debugfile,"%s SMTP Error reading banner: %s\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
}
|
||||
doSMTPExit (ptcx, me);
|
||||
return NULL;
|
||||
}
|
||||
if (isSmtpResponseOK(respBuffer) == 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->banner.errs++;
|
||||
returnerr(debugfile, "%s Got SMTP ERROR response [%.99s]\n",
|
||||
ptcx->errMsg, respBuffer);
|
||||
}
|
||||
doSMTPExit (ptcx, me);
|
||||
return NULL;
|
||||
}
|
||||
D_PRINTF(debugfile,"read connect response\n");
|
||||
|
||||
|
||||
if (pish->flags & useEHLO) {
|
||||
/* send extended EHLO */
|
||||
sprintf(command, "EHLO %s" CRLF, gs_thishostname);
|
||||
} else {
|
||||
/* send normal HELO */
|
||||
sprintf(command, "HELO %s" CRLF, gs_thishostname);
|
||||
}
|
||||
event_start(ptcx, &stats->cmd);
|
||||
/* LMTP addition */
|
||||
if (pish->flags & useLMTP) {
|
||||
int len = 0;
|
||||
char *resp = respBuffer;
|
||||
/* send extended LHLO directly to lmtp*/
|
||||
sprintf(command, "LHLO %s" CRLF, gs_thishostname);
|
||||
T_PRINTF(ptcx->logfile, command, strlen (command), "SMTP SendCommand");
|
||||
if ((rc = sendCommand(ptcx, ptcx->sock, command)) < 0)
|
||||
goto end_helo;
|
||||
*respBuffer = '\0';
|
||||
while ((rc = retryRead(ptcx, ptcx->sock, respBuffer + len, sizeof(respBuffer) - len)) > 0) {
|
||||
/* Sean O'Rourke: handle multi-line response to LHLO */
|
||||
len += rc;
|
||||
if (respBuffer[len-1] != '\n')
|
||||
continue;
|
||||
resp = respBuffer + len - 2;
|
||||
while (resp > respBuffer && *resp != '\n')
|
||||
resp--;
|
||||
if (resp > respBuffer)
|
||||
resp++;
|
||||
|
||||
if (isSmtpResponse(resp))
|
||||
break;
|
||||
else {
|
||||
D_PRINTF(debugfile, "lhlo: no response in `%s'\n", respBuffer);
|
||||
strcpy(respBuffer, resp);
|
||||
len = strlen(resp);
|
||||
}
|
||||
}
|
||||
T_PRINTF(ptcx->logfile, resp, strlen (resp),
|
||||
"SMTP response");
|
||||
if (rc > 0) {
|
||||
if (isSmtpResponseOK(resp))
|
||||
rc = 0;
|
||||
else
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
else if (pish->flags & useEHLO) {
|
||||
int len = 0;
|
||||
char *resp = respBuffer;
|
||||
/* send extended EHLO */
|
||||
sprintf(command, "EHLO %s" CRLF, gs_thishostname);
|
||||
T_PRINTF(ptcx->logfile, command, strlen (command), "SMTP SendCommand");
|
||||
if ((rc = sendCommand(ptcx, ptcx->sock, command)) < 0)
|
||||
goto end_helo;
|
||||
*respBuffer = '\0';
|
||||
while ((rc = retryRead(ptcx, ptcx->sock, respBuffer + len, sizeof(respBuffer) - len)) > 0) {
|
||||
/* Sean O'Rourke: handle multi-line response to EHLO */
|
||||
len += rc;
|
||||
if (respBuffer[len-1] != '\n')
|
||||
continue;
|
||||
resp = respBuffer + len - 2;
|
||||
while (resp > respBuffer && *resp != '\n')
|
||||
resp--;
|
||||
if (resp > respBuffer)
|
||||
resp++;
|
||||
|
||||
if (isSmtpResponse(resp))
|
||||
break;
|
||||
else {
|
||||
D_PRINTF(debugfile, "ehlo: no response in `%s'\n", respBuffer);
|
||||
strcpy(respBuffer, resp);
|
||||
len = strlen(resp);
|
||||
}
|
||||
}
|
||||
T_PRINTF(ptcx->logfile, resp, strlen (resp),
|
||||
"SMTP response");
|
||||
if (rc > 0) {
|
||||
if (isSmtpResponseOK(resp))
|
||||
rc = 0;
|
||||
else
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* send normal HELO */
|
||||
sprintf(command, "HELO %s" CRLF, gs_thishostname);
|
||||
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
}
|
||||
end_helo:
|
||||
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->cmd.errs++;
|
||||
trimEndWhite (command);
|
||||
returnerr(debugfile, "%s SMTP/LMTP HELO/EHLO/LHLO [%.99s] ERROR reading response [%.99s]\n",
|
||||
ptcx->errMsg, command, respBuffer);
|
||||
}
|
||||
doSMTPExit (ptcx, me);
|
||||
return NULL;
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->cmd.errs++;
|
||||
trimEndWhite (command);
|
||||
returnerr(debugfile, "%s SMTP HELO/EHLO [%.99s] ERROR reading response [%.99s]\n",
|
||||
ptcx->errMsg, command, respBuffer);
|
||||
}
|
||||
doSMTPExit (ptcx, me);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pish->flags & useAUTHPLAIN) {
|
||||
@@ -1335,28 +1055,6 @@ sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
|
||||
if (!pish->useTLS)
|
||||
goto end_tls;
|
||||
|
||||
D_PRINTF(debugfile, "Looking for STARTTLS\n");
|
||||
if (strstr(respBuffer, "STARTTLS") != NULL) {
|
||||
SOCKET newsock;
|
||||
D_PRINTF(debugfile, "trying STARTTLS\n");
|
||||
event_start(ptcx, &stats->cmd);
|
||||
newsock = starttls(ptcx, cmd, ptcx->sock);
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (BADSOCKET(newsock)) {
|
||||
D_PRINTF(stderr, "STARTTLS failed\n");
|
||||
stats->cmd.errs++;
|
||||
} else {
|
||||
ptcx->sock = newsock;
|
||||
}
|
||||
}
|
||||
end_tls:
|
||||
|
||||
#endif /* SOCK_SSL */
|
||||
return me;
|
||||
}
|
||||
|
||||
@@ -1373,18 +1071,11 @@ sendSMTPLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystat
|
||||
int rc, jj;
|
||||
long addressNum;
|
||||
long domainNum;
|
||||
int numBytes;
|
||||
int numRecips;
|
||||
int numBytes;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
smtp_file_t *fileEntry;
|
||||
|
||||
assert(ptcx != NULL);
|
||||
assert(cmd != NULL);
|
||||
assert(ptimer != NULL);
|
||||
assert(mystate != NULL);
|
||||
assert(ptimer->data != NULL);
|
||||
|
||||
/* send MAIL FROM:<username> */
|
||||
if (pish->fileCount > 1) { /* randomly pick file */
|
||||
int ff;
|
||||
@@ -1403,45 +1094,19 @@ sendSMTPLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystat
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->cmd.errs++;
|
||||
trimEndWhite (command);
|
||||
returnerr(debugfile, "%s SMTP FROM [%.99s], ERROR reading [%.99s] response [%.99s]\n",
|
||||
PSTR(ptcx->errMsg), command, respBuffer);
|
||||
ptcx->errMsg, command, respBuffer);
|
||||
}
|
||||
doSMTPExit (ptcx, me);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* send RCPT TO:<username> for each recipient */
|
||||
numRecips = (int)rint(sample(pish->numRecipients));
|
||||
if (numRecips == 0) {
|
||||
/*
|
||||
** XXX: make sure we don't have zero-recipient messages.
|
||||
** We could just set numRecips to 1, but this screws up the
|
||||
** mean on our distribution. Try doing an SMTP RSET instead.
|
||||
*/
|
||||
fprintf(stderr, "RSET for 0-recipient message\n");
|
||||
sprintf(command, "RSET%s", CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->cmd.errs++;
|
||||
trimEndWhite (command);
|
||||
returnerr(debugfile,
|
||||
"RSET [%.99s], ERROR reading response [%.99s]\n",
|
||||
ptcx->errMsg, respBuffer);
|
||||
}
|
||||
doSMTPExit (ptcx, me);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (jj = 0; jj < numRecips; jj++) {
|
||||
for (jj = 0; jj < pish->numRecipients; jj++) {
|
||||
/* generate a random recipient (but with an account on the server) */
|
||||
|
||||
domainNum = rangeNext (&stats->domainRange, stats->lastDomain);
|
||||
@@ -1455,28 +1120,24 @@ sendSMTPLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystat
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc < 0) {
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->cmd.errs++;
|
||||
trimEndWhite (command);
|
||||
returnerr(debugfile, "%s SMTP RCPT [%.99s], ERROR response [%.99s]\n",
|
||||
returnerr(debugfile, "%s SMTP RCPT [%.99s], ERROR reading [%.99s] response [%.99s]\n",
|
||||
ptcx->errMsg, command, respBuffer);
|
||||
}
|
||||
/*
|
||||
** XXX: we always give up here. Should probably check
|
||||
** for 4xx and try next recipient.
|
||||
*/
|
||||
doSMTPExit (ptcx, me);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* send DATA */
|
||||
sprintf(command, "DATA%s", CRLF);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
sprintf(command, "DATA%s", CRLF);
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
if (rc == -1 || respBuffer[0] != '3') {
|
||||
if (doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer)) == -1 ||
|
||||
respBuffer[0] != '3') {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->cmd.errs++;
|
||||
returnerr(debugfile, "%s SMTP DATA ERROR, response [%.99s]\n",
|
||||
@@ -1490,15 +1151,10 @@ sendSMTPLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystat
|
||||
|
||||
/* send message */
|
||||
event_start(ptcx, &stats->msgwrite);
|
||||
if (pish->filename)
|
||||
numBytes = sendFile(ptcx, ptcx->sock,
|
||||
numBytes = sendFile(ptcx, ptcx->sock,
|
||||
NULL,
|
||||
fileEntry->filename, fileEntry->offset,
|
||||
MSG_TRAILER);
|
||||
#ifdef AUTOGEN
|
||||
else
|
||||
numBytes = generateMessage(ptcx, pish);
|
||||
#endif
|
||||
if (numBytes == -1) {
|
||||
event_stop(ptcx, &stats->msgwrite);
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
@@ -1529,19 +1185,11 @@ void
|
||||
sendSMTPEnd(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
||||
{
|
||||
doSMTP_state_t *me = (doSMTP_state_t *)mystate;
|
||||
char command[MAX_COMMAND_LEN];
|
||||
char command[MAXCOMMANDLEN];
|
||||
char respBuffer[MAX_RESPONSE_LEN];
|
||||
int rc;
|
||||
pish_stats_t *stats;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
|
||||
|
||||
assert(ptcx != NULL);
|
||||
assert(cmd != NULL);
|
||||
assert(ptimer != NULL);
|
||||
assert(mystate != NULL);
|
||||
assert(ptimer->data != NULL);
|
||||
|
||||
stats = (pish_stats_t *)ptimer->data;
|
||||
if (BADSOCKET(ptcx->sock)) return; /* closed by previous error */
|
||||
|
||||
/* send QUIT */
|
||||
@@ -1549,7 +1197,7 @@ sendSMTPEnd(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate
|
||||
event_start(ptcx, &stats->logout);
|
||||
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->logout);
|
||||
if (rc < 0) {
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->logout.errs++;
|
||||
returnerr(debugfile, "%s SMTP QUIT ERROR, response [%.99s]\n",
|
||||
@@ -1566,5 +1214,5 @@ doSMTPExit (ptcx_t ptcx, doSMTP_state_t *me)
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
|
||||
xfree (me);
|
||||
myfree (me);
|
||||
}
|
||||
|
||||
@@ -1,479 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#include <sched.h>
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
SOCKET BADSOCKET_VALUE = (SOCKET)-1;
|
||||
|
||||
/*
|
||||
** Real sockets
|
||||
*/
|
||||
|
||||
struct sock_socket
|
||||
{
|
||||
socktype_t type;
|
||||
_SOCKET fd;
|
||||
};
|
||||
|
||||
SOCKET
|
||||
sock_open(int fd)
|
||||
{
|
||||
struct sock_socket *ret = XALLOC(struct sock_socket);
|
||||
ret->type = &SOCK_SOCKET;
|
||||
ret->fd = fd;
|
||||
return (SOCKET)ret;
|
||||
}
|
||||
|
||||
static int
|
||||
sock_read(SOCKET this, char *buf, int len)
|
||||
{
|
||||
struct sock_socket *s = (struct sock_socket*)this;
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
return _NETREAD(s->fd, buf, len);
|
||||
}
|
||||
|
||||
static int
|
||||
sock_write(SOCKET this, char *buf, int len)
|
||||
{
|
||||
struct sock_socket *s = (struct sock_socket*)this;
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
return _NETWRITE(s->fd, buf, len);
|
||||
}
|
||||
|
||||
static void
|
||||
sock_close(SOCKET this)
|
||||
{
|
||||
struct sock_socket *s = (struct sock_socket*)this;
|
||||
if (this == BADSOCKET_VALUE)
|
||||
return;
|
||||
_NETCLOSE(s->fd);
|
||||
xfree(s);
|
||||
}
|
||||
|
||||
static _SOCKET
|
||||
sock_getfd(SOCKET this)
|
||||
{
|
||||
struct sock_socket *s = (struct sock_socket*)this;
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
assert(s->fd >= -1);
|
||||
return s->fd;
|
||||
}
|
||||
|
||||
struct socktype SOCK_SOCKET =
|
||||
{
|
||||
&sock_read,
|
||||
&sock_write,
|
||||
&sock_close,
|
||||
&sock_getfd
|
||||
};
|
||||
|
||||
#ifdef SOCK_LINESPEED
|
||||
|
||||
/*
|
||||
** Slow sockets
|
||||
*/
|
||||
|
||||
typedef struct ls_socket
|
||||
{
|
||||
socktype_t type;
|
||||
SOCKET socket;
|
||||
int latency;
|
||||
int bandwidth;
|
||||
} ls_socket_t;
|
||||
|
||||
/* time_left < LS_DONT_WAIT => return right away */
|
||||
#define LS_DONT_WAIT 10
|
||||
/* LS_DONT_WAIT <= time_left < LS_SCHED_YIELD => just sched_yield() */
|
||||
#define LS_SCHED_YIELD 100
|
||||
#define LS_BLOCKSIZE (8192) /* largest block-size to transfer at once */
|
||||
|
||||
#define OPTIME(S, N) (((S)->bandwidth > 0) \
|
||||
?((S)->latency + ((N)*1000)/(S)->bandwidth) \
|
||||
:0)
|
||||
|
||||
#define TV_SUB(A, B) (((A).tv_sec - (B).tv_sec)*1000 \
|
||||
+ ((A).tv_usec - (B).tv_usec)/1000)
|
||||
|
||||
#define WASTE_TIME(T) do { \
|
||||
if((T) >= LS_DONT_WAIT) \
|
||||
{ \
|
||||
if((T) < LS_SCHED_YIELD) \
|
||||
sched_yield(); \
|
||||
else \
|
||||
MS_usleep((T)*1000); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MIGHT_WAIT(T) ((T) >= LS_DONT_WAIT)
|
||||
|
||||
SOCKET
|
||||
ls_open(SOCKET fd, void *_cmd)
|
||||
{
|
||||
pish_command_t *cmd = (pish_command_t*)_cmd;
|
||||
ls_socket_t *s;
|
||||
int buf = LS_BLOCKSIZE;
|
||||
|
||||
assert(fd != BADSOCKET_VALUE);
|
||||
|
||||
if((setsockopt(SOCK_FD(fd), SOL_SOCKET, SO_RCVBUF, &buf, sizeof(buf)) < 0)
|
||||
|| (setsockopt(SOCK_FD(fd), SOL_SOCKET, SO_SNDBUF, &buf, sizeof(buf)) < 0))
|
||||
return NULL;
|
||||
|
||||
s = XALLOC(struct ls_socket);
|
||||
s->type = &LS_SOCKET;
|
||||
s->socket = fd;
|
||||
s->latency = sample(cmd->latency);
|
||||
s->bandwidth = sample(cmd->bandwidth);
|
||||
return (SOCKET)s;
|
||||
}
|
||||
|
||||
static int
|
||||
delayed_read(SOCKET this, char *buf, int count)
|
||||
{
|
||||
struct timeval start, stop;
|
||||
int ret;
|
||||
int time_left;
|
||||
struct ls_socket *sock = (struct ls_socket*)this;
|
||||
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
|
||||
if(count > LS_BLOCKSIZE)
|
||||
count = LS_BLOCKSIZE;
|
||||
time_left = OPTIME(sock, count);
|
||||
if(MIGHT_WAIT(time_left))
|
||||
{
|
||||
int optime, save_errno;
|
||||
gettimeofday(&start, NULL);
|
||||
ret = NETREAD(sock->socket, buf, count);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
save_errno = errno;
|
||||
/* update to reflect actual bytes read: */
|
||||
gettimeofday(&stop, NULL);
|
||||
time_left = OPTIME(sock, ret);
|
||||
optime = TV_SUB(stop, start);
|
||||
time_left -= optime;
|
||||
WASTE_TIME(time_left);
|
||||
errno = save_errno;
|
||||
return ret;
|
||||
}
|
||||
return NETREAD(sock->socket, buf, count);
|
||||
}
|
||||
|
||||
static int
|
||||
delayed_write(SOCKET this, char *buf, int count)
|
||||
{
|
||||
struct timeval start, stop;
|
||||
int ret;
|
||||
int time_left;
|
||||
struct ls_socket *sock = (struct ls_socket*)this;
|
||||
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
|
||||
if(count > LS_BLOCKSIZE)
|
||||
count = LS_BLOCKSIZE;
|
||||
time_left = OPTIME(sock, count);
|
||||
if(MIGHT_WAIT(time_left))
|
||||
{
|
||||
int optime, save_errno;
|
||||
gettimeofday(&start, NULL);
|
||||
ret = NETWRITE(sock->socket, buf, count);
|
||||
if(ret <= 0)
|
||||
return ret;
|
||||
save_errno = errno;
|
||||
gettimeofday(&stop, NULL);
|
||||
optime = TV_SUB(stop, start);
|
||||
time_left -= optime;
|
||||
WASTE_TIME(time_left);
|
||||
return ret;
|
||||
}
|
||||
return NETWRITE(sock->socket, buf, count);
|
||||
}
|
||||
|
||||
static void
|
||||
ls_close(SOCKET this)
|
||||
{
|
||||
struct ls_socket *sock = (struct ls_socket*)this;
|
||||
if (this != BADSOCKET_VALUE && sock->socket)
|
||||
{
|
||||
NETCLOSE(sock->socket);
|
||||
}
|
||||
xfree(sock);
|
||||
}
|
||||
|
||||
static _SOCKET
|
||||
ls_getfd(SOCKET this)
|
||||
{
|
||||
struct ls_socket *sock = (struct ls_socket*)this;
|
||||
int fd;
|
||||
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
|
||||
fd = SOCK_FD(sock->socket);
|
||||
assert(fd >= -1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct socktype LS_SOCKET =
|
||||
{
|
||||
&delayed_read,
|
||||
&delayed_write,
|
||||
&ls_close,
|
||||
&ls_getfd
|
||||
};
|
||||
|
||||
#endif /* SOCK_LINESPEED */
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
/*
|
||||
** SSL sockets
|
||||
*/
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
struct ssl_socket
|
||||
{
|
||||
socktype_t type;
|
||||
SSL *ssl;
|
||||
SOCKET sock;
|
||||
};
|
||||
|
||||
static void
|
||||
mysslerr(FILE *f, SSL *ssl, int ret)
|
||||
{
|
||||
unsigned long err = SSL_get_error(ssl, ret);
|
||||
fprintf(f, "ssl_socket(%d): ", SSL_get_fd(ssl));
|
||||
switch(err)
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
fprintf(f, "no error\n");
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
fprintf(f, "zero return\n");
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
fprintf(f, "want read\n");
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
fprintf(f, "want write\n");
|
||||
break;
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
fprintf(f, "want x509\n");
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
fprintf(f, "syscall: %s\n", strerror(errno));
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
fprintf(f, "ssl problem...\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static RSA *
|
||||
tmp_rsa_key(SSL *ssl, int export, int keylen)
|
||||
{
|
||||
static RSA *rsa_tmp = NULL;
|
||||
if (rsa_tmp == NULL &&
|
||||
(rsa_tmp = RSA_generate_key(keylen, RSA_F4,
|
||||
NULL, NULL)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "tmp_rsa_key(%p, %d, %d): RSA error\n",
|
||||
ssl, export, keylen);
|
||||
}
|
||||
return rsa_tmp;
|
||||
}
|
||||
|
||||
int
|
||||
eternal_1(X509_STORE_CTX * x509)
|
||||
{
|
||||
/* ignore cert failures */
|
||||
return 1;
|
||||
}
|
||||
|
||||
SOCKET
|
||||
ssl_open(SOCKET sock, void *_cmd)
|
||||
{
|
||||
pish_command_t *cmd = (pish_command_t*)_cmd;
|
||||
static int sslinit = 0;
|
||||
SSL_CTX *ctx = NULL;
|
||||
SSL *ssl = NULL;
|
||||
int ret = 0;
|
||||
int fd;
|
||||
struct ssl_socket *retval = NULL;
|
||||
char *blame = "?";
|
||||
char *my_private_key = cmd->key;
|
||||
char *my_cert = cmd->cert;
|
||||
|
||||
assert(sock != BADSOCKET_VALUE);
|
||||
assert(_cmd != NULL);
|
||||
|
||||
fd = SOCK_FD(sock);
|
||||
/* initialize ctx */
|
||||
/* XXX: not threadsafe */
|
||||
if (ctx == NULL)
|
||||
{
|
||||
if (!sslinit)
|
||||
{
|
||||
SSL_library_init();
|
||||
/* just go ahead and do this now. */
|
||||
SSL_load_error_strings();
|
||||
sslinit = 1;
|
||||
}
|
||||
if ((ctx = SSL_CTX_new(SSLv23_client_method())) == NULL)
|
||||
{
|
||||
blame = "SSL_CTX_new";
|
||||
goto error;
|
||||
}
|
||||
/* do other initialization: */
|
||||
SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_key);
|
||||
/* Private Key */
|
||||
if (my_private_key != NULL)
|
||||
{
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, my_private_key,
|
||||
SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
blame = "SSL_CTX_use_PrivateKey_file";
|
||||
goto error;
|
||||
}
|
||||
if (SSL_CTX_check_private_key(ctx) <= 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"ssl_open(%d): Warning: invalid private key\n", fd);
|
||||
ERR_print_errors_fp(stderr);
|
||||
}
|
||||
}
|
||||
/* Cert */
|
||||
if (my_cert != NULL
|
||||
&& SSL_CTX_use_certificate_file(ctx, my_cert, SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
blame = "SSL_CTX_use_certificate_file";
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* CA's */
|
||||
SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_key);
|
||||
SSL_CTX_set_cert_verify_callback(ctx, eternal_1, NULL);
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
/* if we get here, we know ctx has been successfully initialized */
|
||||
/* initialize ssl */
|
||||
if ((ssl = SSL_new(ctx)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "ssl_open(%d): ssl_new error\n", fd);
|
||||
/* error */
|
||||
return BADSOCKET_VALUE;
|
||||
}
|
||||
if ((ret = SSL_set_fd(ssl, fd)) <= 0)
|
||||
{
|
||||
blame = "SSL_set_fd";
|
||||
goto error;
|
||||
}
|
||||
SSL_set_connect_state(ssl);
|
||||
if ((ret = SSL_connect(ssl)) <= 0)
|
||||
{
|
||||
blame = "SSL_connect";
|
||||
goto error;
|
||||
}
|
||||
retval = XALLOC(struct ssl_socket);
|
||||
retval->type = &SSL_SOCKET;
|
||||
retval->ssl = ssl;
|
||||
retval->sock = sock;
|
||||
return (SOCKET)retval;
|
||||
error:
|
||||
{
|
||||
fprintf(stderr, "ssl_open(%d) failed in %s:\n", fd, blame);
|
||||
mysslerr(stderr, ssl, ret);
|
||||
return BADSOCKET_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ssl_read(SOCKET this, char *buf, int len)
|
||||
{
|
||||
struct ssl_socket *s = (struct ssl_socket*)this;
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
return SSL_read(s->ssl, buf, len);
|
||||
}
|
||||
|
||||
static int
|
||||
ssl_write(SOCKET this, char *buf, int len)
|
||||
{
|
||||
struct ssl_socket *s = (struct ssl_socket*)this;
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
return SSL_write(s->ssl, buf, len);
|
||||
}
|
||||
|
||||
static void
|
||||
ssl_close(SOCKET this)
|
||||
{
|
||||
struct ssl_socket *s = (struct ssl_socket*)this;
|
||||
int ret;
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
if ((ret = SSL_shutdown(s->ssl)) <= 0)
|
||||
{
|
||||
fprintf(stderr, "ssl_close(%d): ", SOCK_FD(this));
|
||||
mysslerr(stderr, s->ssl, ret);
|
||||
}
|
||||
SSL_free(s->ssl);
|
||||
NETCLOSE(s->sock);
|
||||
}
|
||||
|
||||
static _SOCKET
|
||||
ssl_getfd(SOCKET this)
|
||||
{
|
||||
struct ssl_socket *s = (struct ssl_socket*)this;
|
||||
int fd;
|
||||
|
||||
assert(this != BADSOCKET_VALUE);
|
||||
|
||||
fd = SSL_get_fd(s->ssl);
|
||||
assert(fd >= -1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
struct socktype SSL_SOCKET =
|
||||
{
|
||||
&ssl_read,
|
||||
&ssl_write,
|
||||
&ssl_close,
|
||||
&ssl_getfd
|
||||
};
|
||||
|
||||
#endif /* SOCK_SSL */
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _socket_h
|
||||
#define _socket_h
|
||||
|
||||
/*
|
||||
** Socket wrapper support
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
struct socktype;
|
||||
|
||||
typedef struct SOCKET_s
|
||||
{
|
||||
struct socktype*type;
|
||||
void *sock[1];
|
||||
} *SOCKET;
|
||||
|
||||
extern SOCKET BADSOCKET_VALUE;
|
||||
|
||||
/* Functions a socket must implement: */
|
||||
typedef int (*read_t)(SOCKET, char *, int);
|
||||
typedef int (*write_t)(SOCKET, char *, int);
|
||||
typedef void (*close_t)(SOCKET);
|
||||
typedef _SOCKET (*getfd_t)(SOCKET);
|
||||
|
||||
typedef struct socktype
|
||||
{
|
||||
read_t read;
|
||||
write_t write;
|
||||
close_t close;
|
||||
getfd_t getfd;
|
||||
} * socktype_t;
|
||||
|
||||
#define NETREAD(S, B, L) ((S)->type->read((S), (B), (L)))
|
||||
#define NETWRITE(S, B, L) ((S)->type->write((S), (B), (L)))
|
||||
#define NETCLOSE(S) ((S)->type->close(S))
|
||||
#define BADSOCKET(S) (((S) == BADSOCKET_VALUE) || _BADSOCKET(SOCK_FD(S)))
|
||||
#define BADSOCKET_ERRNO(sock) BADSOCKET(sock)
|
||||
/* #define INIT_SOCKET(sock, host) init_socket((sock), (host)) */
|
||||
#define SOCK_FD(s) ((s)->type->getfd(s))
|
||||
|
||||
/* Basic sockets */
|
||||
extern struct socktype SOCK_SOCKET;
|
||||
SOCKET sock_open(int fd);
|
||||
|
||||
#ifdef SOCK_SSL
|
||||
extern struct socktype SSL_SOCKET;
|
||||
extern SOCKET ssl_open(SOCKET sock, void* pish);
|
||||
#define SSL_INIT(S, cmd) (void)((S) = ssl_open((S), cmd))
|
||||
#else /* SOCK_SSL */
|
||||
#define SSL_INIT(S, cmd) (void)0
|
||||
#endif /* SOCK_SSL */
|
||||
|
||||
#ifdef SOCK_LINESPEED
|
||||
extern struct socktype LS_SOCKET;
|
||||
extern SOCKET ls_open(SOCKET fd, void*);
|
||||
#define LS_INIT(S, cmd) (void)((S) = ls_open((S), (cmd)))
|
||||
#else /* SOCK_LINESPEED */
|
||||
#define LS_INIT(S, cmd) (void)0
|
||||
#endif /* SOCK_LINESPEED */
|
||||
|
||||
#endif /* _socket_h */
|
||||
@@ -21,7 +21,6 @@
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -67,11 +66,12 @@ void sock_cleanup(void) {
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* neither sleep or usleep re-start if interrupted */
|
||||
void
|
||||
MS_sleep(unsigned int secs)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
Sleep(secs*1000);
|
||||
Sleep(secs * 1000);
|
||||
#else
|
||||
struct timeval sleeptime;
|
||||
|
||||
@@ -79,7 +79,8 @@ MS_sleep(unsigned int secs)
|
||||
|
||||
sleeptime.tv_sec = secs;
|
||||
sleeptime.tv_usec = 0;
|
||||
if (select(0, NULL, NULL, NULL, &sleeptime) < 0) {
|
||||
if (select( (int)NULL, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
|
||||
&sleeptime ) < 0) {
|
||||
D_PRINTF (stderr, "MS_sleep %lu returned early\n", secs);
|
||||
}
|
||||
#endif
|
||||
@@ -195,15 +196,11 @@ sysdep_thread_join(THREAD_ID id, int *pstatus)
|
||||
|
||||
#define MAX_TRYFDS (64*1024)
|
||||
|
||||
/*
|
||||
** Sean O'Rourke TODO: try to guess how much of each resource we need, and
|
||||
** warn if we cannot get at least that much.
|
||||
*/
|
||||
|
||||
void
|
||||
crank_limits(void)
|
||||
{
|
||||
struct rlimit rlim;
|
||||
int cur_lim;
|
||||
int rc;
|
||||
|
||||
#ifdef __OSF1__
|
||||
@@ -217,31 +214,6 @@ crank_limits(void)
|
||||
|
||||
D_PRINTF(stderr, "attempting to increase our hard limit (up to %d)\n", MAX_TRYFDS);
|
||||
|
||||
/* Sean O'Rourke: simpler rlimit bump, courtesy of proxy */
|
||||
rlim.rlim_max = RLIM_INFINITY;
|
||||
rlim.rlim_cur = RLIM_INFINITY;
|
||||
rc = setrlimit(RLIMIT_NOFILE, &rlim);
|
||||
(void) getrlimit(RLIMIT_NOFILE, &rlim);
|
||||
if (rc < 0) {
|
||||
D_PRINTF (stderr, "setrlimit(RLIMIT_NOFILE): %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
D_PRINTF (stderr, "limited to %d files\n", rlim.rlim_cur);
|
||||
|
||||
/* Sean O'Rourke: also bump nprocs, since procs == threads on linux */
|
||||
rlim.rlim_max = RLIM_INFINITY;
|
||||
rlim.rlim_cur = RLIM_INFINITY;
|
||||
#ifdef __LINUX__
|
||||
rc = setrlimit(RLIMIT_NPROC, &rlim);
|
||||
(void) getrlimit(RLIMIT_NPROC, &rlim);
|
||||
if (rc < 0) {
|
||||
D_PRINTF (stderr, "setrlimit(RLIMIT_NPROC): %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
D_PRINTF (stderr, "limited to %d procs\n", rlim.rlim_cur);
|
||||
#endif /* __AIX__ */
|
||||
#if 0
|
||||
/* Sean O'Rourke XXX: why were they going through these contortions? */
|
||||
rc = getrlimit(RLIMIT_NOFILE, &rlim);
|
||||
if (rc == -1) {
|
||||
returnerr(stderr, "getrlimit()");
|
||||
@@ -282,7 +254,6 @@ crank_limits(void)
|
||||
D_PRINTF (stderr, "RLIMIT_NOFILE = %d. max processes/threads ~ %d\n",
|
||||
rlim.rlim_cur, rlim.rlim_cur-10);
|
||||
}
|
||||
#endif /* 0 */
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -352,10 +323,10 @@ setup_signal_handlers(void)
|
||||
|
||||
}
|
||||
#else
|
||||
signal(SIGALRM, alarmHandler);
|
||||
signal(SIGHUP, hupHandler);
|
||||
signal(SIGTERM, hupHandler);
|
||||
signal(SIGPIPE, nullHandler);
|
||||
sigset(SIGALRM, alarmHandler);
|
||||
sigset(SIGHUP, hupHandler);
|
||||
sigset(SIGTERM, hupHandler);
|
||||
sigset(SIGPIPE, nullHandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Mike Blakely
|
||||
* David Shak
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -76,13 +75,13 @@
|
||||
|
||||
/* encapsulation of minor UNIX/WIN NT differences */
|
||||
#ifdef _WIN32
|
||||
#define _NETREAD(sock, buf, len) recv(sock, buf, len, 0)
|
||||
#define _NETWRITE(sock, buf, len) send(sock, buf, len, 0)
|
||||
#define _NETCLOSE(sock) closesocket(sock)
|
||||
#define NETREAD(sock, buf, len) recv(sock, buf, len, 0)
|
||||
#define NETWRITE(sock, buf, len) send(sock, buf, len, 0)
|
||||
#define NETCLOSE(sock) closesocket(sock)
|
||||
#define OUTPUT_WRITE(sock, buf, len) write(sock, buf, len)
|
||||
#define _BADSOCKET(sock) ((sock) == INVALID_SOCKET)
|
||||
#define _BADSOCKET_ERRNO(sock) BADSOCKET(sock)
|
||||
#define _BADSOCKET_VALUE INVALID_SOCKET
|
||||
#define BADSOCKET(sock) ((sock) == INVALID_SOCKET)
|
||||
#define BADSOCKET_ERRNO(sock) BADSOCKET(sock)
|
||||
#define BADSOCKET_VALUE INVALID_SOCKET
|
||||
#define S_ADDR S_un.S_addr
|
||||
#define GET_ERROR WSAGetLastError()
|
||||
#define SET_ERROR(err) WSASetLastError(err)
|
||||
@@ -113,13 +112,13 @@ extern void sock_cleanup(void);
|
||||
|
||||
#define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
|
||||
|
||||
#define _NETREAD(sock, buf, len) read(sock, buf, len)
|
||||
#define _NETWRITE(sock, buf, len) write(sock, buf, len)
|
||||
#define _NETCLOSE(sock) close(sock)
|
||||
#define NETREAD(sock, buf, len) read(sock, buf, len)
|
||||
#define NETWRITE(sock, buf, len) write(sock, buf, len)
|
||||
#define NETCLOSE(sock) close(sock)
|
||||
#define OUTPUT_WRITE(sock, buf, len) write(sock, buf, len)
|
||||
#define _BADSOCKET(sock) ((sock) < 0)
|
||||
#define _BADSOCKET_ERRNO(sock) (BADSOCKET(sock) || errno)
|
||||
#define _BADSOCKET_VALUE (-1)
|
||||
#define BADSOCKET(sock) ((sock) < 0)
|
||||
#define BADSOCKET_ERRNO(sock) (BADSOCKET(sock) || errno)
|
||||
#define BADSOCKET_VALUE (-1)
|
||||
#define S_ADDR s_addr
|
||||
#define GET_ERROR errno
|
||||
#define SET_ERROR(err) (errno = (err))
|
||||
@@ -150,26 +149,12 @@ extern long osf_lrand48_r(void);
|
||||
#define FILENAME_SIZE 1024
|
||||
#define HAVE_VPRINTF 1
|
||||
|
||||
typedef int _SOCKET;
|
||||
|
||||
#if 0
|
||||
typedef _SOCKET SOCKET;
|
||||
#define NETREAD _NETREAD
|
||||
#define NETWRITE _NETWRITE
|
||||
#define NETCLOSE _NETCLOSE
|
||||
#define BADSOCKET _BADSOCKET
|
||||
#define BADSOCKET_ERRNO _BADSOCKET_ERRNO
|
||||
#define BADSOCKET_VALUE _BADSOCKET_VALUE
|
||||
#define INIT_SOCKET(sock, host) (sock)
|
||||
#define SOCK_FD(s) (s)
|
||||
#endif /* 0 (was !LINESPEED) */
|
||||
|
||||
typedef int SOCKET;
|
||||
#define min(a,b) (((a) < (b)) ? a : b)
|
||||
#define max(a,b) (((a) > (b)) ? a : b)
|
||||
|
||||
#define THREAD_RET void *
|
||||
#ifdef USE_PTHREADS
|
||||
#include <pthread.h>
|
||||
#define THREAD_ID pthread_t
|
||||
#else
|
||||
#define THREAD_ID int
|
||||
|
||||
@@ -1,748 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
#include "http-util.h"
|
||||
#include "xalloc.h"
|
||||
#include "sb.h"
|
||||
|
||||
/* flags definitions */
|
||||
#define leaveMailOnServer 0x01
|
||||
|
||||
#define WEBMAIL_UPDATE 30 * 1000 /* 30-second default check interval */
|
||||
#define COOKIE "Cookie: "
|
||||
|
||||
typedef pish_stats_t web_stats_t;
|
||||
typedef pish_command_t web_command_t;
|
||||
|
||||
/*
|
||||
** WEB_USER functions
|
||||
*/
|
||||
|
||||
typedef struct web_user_s
|
||||
{
|
||||
char *cookies;
|
||||
int usernum;
|
||||
int domainnum;
|
||||
int needs_expunge;
|
||||
} web_user_t;
|
||||
|
||||
static void add_cookie(web_user_t *, char *);
|
||||
static void clear_cookies(web_user_t *);
|
||||
static web_user_t* new_web_user(web_command_t *, web_stats_t *);
|
||||
static void delete_web_user(web_user_t *);
|
||||
|
||||
static void
|
||||
add_cookie(user, cookie)
|
||||
web_user_t *user;
|
||||
char *cookie;
|
||||
{
|
||||
if (user->cookies == NULL)
|
||||
{
|
||||
user->cookies = xalloc(strlen(COOKIE) + strlen(cookie) + 1);
|
||||
sprintf(user->cookies, COOKIE "%s", cookie);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *tmp = xalloc(strlen(user->cookies)
|
||||
+ strlen(cookie)
|
||||
+ 3);
|
||||
sprintf(tmp, "%s; %s", user->cookies, cookie);
|
||||
xfree(user->cookies);
|
||||
user->cookies = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clear_cookies(user)
|
||||
web_user_t *user;
|
||||
{
|
||||
xfree(user->cookies);
|
||||
user->cookies = NULL;
|
||||
}
|
||||
|
||||
static web_user_t*
|
||||
new_web_user(cmd, stats)
|
||||
web_command_t *cmd;
|
||||
web_stats_t *stats;
|
||||
{
|
||||
int domain, login;
|
||||
web_user_t *ret = XALLOC(web_user_t);
|
||||
|
||||
domain = rangeNext(&stats->domainRange, stats->lastDomain);
|
||||
stats->lastDomain = domain;
|
||||
login = rangeNext(&stats->loginRange, stats->lastLogin);
|
||||
stats->lastLogin = login;
|
||||
|
||||
ret->cookies = NULL;
|
||||
ret->usernum = login;
|
||||
ret->domainnum = domain;
|
||||
ret->needs_expunge = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_web_user(user)
|
||||
web_user_t *user;
|
||||
{
|
||||
if(user->cookies)
|
||||
xfree(user->cookies);
|
||||
xfree(user);
|
||||
}
|
||||
|
||||
/*
|
||||
** Webmail parsing routines
|
||||
*/
|
||||
|
||||
typedef struct web_param_s
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
} web_param_t;
|
||||
|
||||
static web_param_t web_defaults[] =
|
||||
{
|
||||
{ "webbase", "/cgi-bin/mailspinner.cgi"},
|
||||
|
||||
{ "webloginformat", "?username=%s&password=%s&login=Login"},
|
||||
{ "webloginpages", "/LeftControl" },
|
||||
{ "webloginpages", "/MailFrames" },
|
||||
{ "webloginpages", "/MailControl" },
|
||||
{ "webloginpages", "/BodyIndex" },
|
||||
|
||||
{ "webdeleteformat", "/BodyIndex?Delete+Selected+Messages.x=1"
|
||||
"&Delete+Selected+Messages.y=1&%s" },
|
||||
{ "webexpunge", "/BodyIndex?Expunge.x=1&Expunge.y=1" },
|
||||
{ "webindex", "/Index/1#new"},
|
||||
{ "weblogout", "/Logout"},
|
||||
{ "webmsgread", "/ReadIndex/%d"},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
WebmailParseNameValue(mailcmd, name, tok)
|
||||
pmail_command_t mailcmd;
|
||||
char *name;
|
||||
char *tok;
|
||||
{
|
||||
web_command_t *cmd = (web_command_t*)mailcmd->data;
|
||||
if (strcmp(name, "webloginpages") == 0)
|
||||
{
|
||||
string_list_t *l = XALLOC(string_list_t);
|
||||
l->next = cmd->webLoginPages;
|
||||
l->value = xstrdup(tok);
|
||||
cmd->webLoginPages = l;
|
||||
}
|
||||
|
||||
else if (strcmp(name, "webloginformat") == 0)
|
||||
cmd->webLoginFormat = xstrdup(tok);
|
||||
else if (strcmp(name, "webbase") == 0)
|
||||
cmd->webBase = xstrdup(tok);
|
||||
else if (strcmp(name, "webindex") == 0)
|
||||
cmd->webIndex = xstrdup(tok);
|
||||
else if (strcmp(name, "weblogout") == 0)
|
||||
cmd->webLogout = xstrdup(tok);
|
||||
else if (strcmp(name, "webmsgread") == 0)
|
||||
cmd->webMsgRead = xstrdup(tok);
|
||||
else if (strcmp(name, "webdeleteformat") == 0)
|
||||
cmd->webDeleteFormat = xstrdup(tok);
|
||||
else if (strcmp(name, "webexpunge") == 0)
|
||||
cmd->webExpunge = xstrdup(tok);
|
||||
else if (strcmp(name, "leavemailonserver") == 0)
|
||||
if (atoi(tok) > 0) {
|
||||
cmd->flags |= leaveMailOnServer;
|
||||
cmd->leaveMailOnServerDist =
|
||||
parse_distrib(tok, (value_parser_t)&atof);
|
||||
}
|
||||
else
|
||||
cmd->flags &= ~leaveMailOnServer;
|
||||
else
|
||||
return pishParseNameValue(mailcmd, name, tok);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
WebmailParseStart(mailcmd, line, defparm)
|
||||
pmail_command_t mailcmd;
|
||||
char *line;
|
||||
param_list_t *defparm;
|
||||
{
|
||||
param_list_t *pp;
|
||||
web_param_t *def;
|
||||
web_command_t *cmd = XALLOC(web_command_t);
|
||||
mailcmd->data = cmd;
|
||||
|
||||
mailcmd->loopDelay = constant_value(WEBMAIL_UPDATE);
|
||||
cmd->hostInfo.portNum = WEBMAIL_PORT;
|
||||
|
||||
/* Fill in the above defaults */
|
||||
for (def = web_defaults; def->name; def++)
|
||||
(void)WebmailParseNameValue (mailcmd, def->name, def->value);
|
||||
|
||||
/* Fill in defaults first, ignore defaults we dont use */
|
||||
for (pp = defparm; pp; pp = pp->next)
|
||||
(void)WebmailParseNameValue (mailcmd, pp->name, pp->value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define REQUIRE_ATTR(cmd, attr) do { \
|
||||
if (!(cmd)->attr) \
|
||||
{ \
|
||||
fprintf(stderr,"webmail: missing " #attr ); \
|
||||
return returnerr(stderr,"webmail: missing " #attr "\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
WebmailParseEnd (mailcmd, section, defparm)
|
||||
pmail_command_t mailcmd;
|
||||
string_list_t *section;
|
||||
param_list_t *defparm;
|
||||
{
|
||||
string_list_t *sp;
|
||||
web_command_t *cmd = (web_command_t *)mailcmd->data;
|
||||
|
||||
/* skip first and last */
|
||||
for (sp = section->next; sp->next; sp = sp->next)
|
||||
{
|
||||
char *name = sp->value;
|
||||
char *tok = name + strcspn(name, " \t=");
|
||||
*tok++ = 0; /* split name off */
|
||||
tok += strspn(tok, " \t=");
|
||||
|
||||
string_tolower(name);
|
||||
tok = string_unquote(tok);
|
||||
|
||||
if (WebmailParseNameValue (mailcmd, name, tok) < 0)
|
||||
{
|
||||
/* not a known attr */
|
||||
fprintf(stderr,"unknown attribute '%s' '%s'\n",
|
||||
name, tok);
|
||||
returnerr(stderr,"unknown attribute '%s' '%s'\n",
|
||||
name, tok);
|
||||
}
|
||||
}
|
||||
|
||||
/* check for some of the required command attrs */
|
||||
if (!cmd->hostInfo.hostName)
|
||||
{
|
||||
fprintf(stderr,"missing webmail server");
|
||||
return returnerr(stderr,"missing webmail server\n");
|
||||
}
|
||||
|
||||
REQUIRE_ATTR(cmd, loginFormat);
|
||||
REQUIRE_ATTR(cmd, passwdFormat);
|
||||
|
||||
REQUIRE_ATTR(cmd, webIndex);
|
||||
REQUIRE_ATTR(cmd, webBase);
|
||||
REQUIRE_ATTR(cmd, webMsgRead);
|
||||
REQUIRE_ATTR(cmd, webLoginFormat);
|
||||
|
||||
/* see if we can resolve the mailserver addr */
|
||||
if (resolve_addrs(cmd->hostInfo.hostName, "tcp",
|
||||
&(cmd->hostInfo.host_phe),
|
||||
&(cmd->hostInfo.host_ppe),
|
||||
&(cmd->hostInfo.host_addr),
|
||||
&(cmd->hostInfo.host_type))) {
|
||||
return returnerr (stderr, "Error resolving hostname '%s'\n",
|
||||
cmd->hostInfo.hostName);
|
||||
}
|
||||
else
|
||||
cmd->hostInfo.resolved = 1;
|
||||
|
||||
rangeSetFirstCount(&cmd->loginRange, cmd->loginRange.first,
|
||||
cmd->loginRange.span, cmd->loginRange.sequential);
|
||||
rangeSetFirstCount(&cmd->domainRange, cmd->domainRange.first,
|
||||
cmd->domainRange.span, cmd->domainRange.sequential);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef REQUIRE_ATTR
|
||||
|
||||
static socket_buffer*
|
||||
web_request(ptcx_t, web_command_t *, char *, web_user_t *);
|
||||
static int
|
||||
web_discard(ptcx_t, web_command_t *, char *, web_user_t *);
|
||||
static int
|
||||
web_login(ptcx_t, web_command_t *, web_stats_t *, web_user_t *);
|
||||
static int
|
||||
web_list_msgs(ptcx_t, web_command_t *, web_stats_t *, web_user_t *, int *, int);
|
||||
static int
|
||||
web_get_msg(ptcx_t, web_command_t *, web_stats_t *, web_user_t *, int);
|
||||
|
||||
static int
|
||||
http_connect (ptcx_t , resolved_addr_t *);
|
||||
|
||||
/*
|
||||
** This is exactly the same as HttpConnect in http-util.c, except
|
||||
** that it doesn't start and stop the event timer.
|
||||
*/
|
||||
static int
|
||||
http_connect(ptcx, hostInfo)
|
||||
ptcx_t ptcx;
|
||||
resolved_addr_t *hostInfo;
|
||||
{
|
||||
int rc=0;
|
||||
|
||||
D_PRINTF(stderr, "http_connect()\n");
|
||||
|
||||
ptcx->sock = connectSocket(ptcx, hostInfo, "tcp");
|
||||
if (BADSOCKET(ptcx->sock))
|
||||
{
|
||||
if (gf_timeexpired < EXIT_FAST)
|
||||
{
|
||||
returnerr(debugfile,
|
||||
"%s<http_connect: connect to %s: %s\n",
|
||||
ptcx->errMsg, hostInfo->hostName,
|
||||
neterrstr());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gf_abortive_close && set_abortive_close(ptcx->sock) != 0)
|
||||
{
|
||||
returnerr(debugfile,
|
||||
"%s<http_connect: WARNING: Could not set abortive close\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static socket_buffer*
|
||||
web_request(ptcx, cmd, url, user)
|
||||
ptcx_t ptcx;
|
||||
web_command_t *cmd;
|
||||
char *url;
|
||||
web_user_t *user;
|
||||
{
|
||||
int len;
|
||||
int content_length = 0;
|
||||
socket_buffer *sb;
|
||||
D_PRINTF(debugfile, "web_request: `%s'\n", url);
|
||||
if (http_connect(ptcx, &cmd->hostInfo) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "web_request: Connect failed: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LS_INIT(ptcx->sock, cmd);
|
||||
|
||||
ptcx->net_timeout = cmd->net_timeout;
|
||||
|
||||
sb = sb_new(ptcx->sock, 1024);
|
||||
snprintf(sb->buf, 1024, "GET %s%s HTTP/1.0" CRLF,
|
||||
cmd->webBase, url);
|
||||
if (user->cookies)
|
||||
{
|
||||
D_PRINTF(debugfile, "web_request: cookies = `%s'\n",
|
||||
user->cookies);
|
||||
strcat(sb->buf, user->cookies);
|
||||
strcat(sb->buf, CRLF);
|
||||
}
|
||||
strcat (sb->buf, CRLF);
|
||||
|
||||
/* event_start(ptcx, stats); */
|
||||
if (sendCommand(ptcx, sb->sock, sb->buf) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "web_request: send failed: %s\n",
|
||||
strerror(errno));
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Find return code */
|
||||
if (sb_discard(ptcx, sb, " ") < 0)
|
||||
goto error_out;
|
||||
|
||||
if (sb->buf[0] != '2')
|
||||
{
|
||||
D_PRINTF(stderr, "web_request: error code %.3s\n", sb->buf);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (sb_discard(ptcx, sb, "\n") < 0
|
||||
|| (len = sb_get(ptcx, sb, "\n")) < 0)
|
||||
goto error_out;
|
||||
|
||||
if (len == 0 || (len == 1 && sb->buf[0] == '\r'))
|
||||
{
|
||||
sb_discard(ptcx, sb, "\n");
|
||||
break;
|
||||
}
|
||||
if (sb->buf[len-1] == '\r')
|
||||
sb->buf[len-1] = '\0';
|
||||
else
|
||||
sb->buf[len] = '\0';
|
||||
|
||||
if (strncasecmp("set-cookie: ", sb->buf,
|
||||
strlen("set-cookie: ")) == 0)
|
||||
add_cookie(user, sb->buf + strlen("set-cookie: "));
|
||||
|
||||
#define LENGTH "content-length: "
|
||||
else if (strncasecmp(LENGTH, sb->buf, strlen(LENGTH)) == 0)
|
||||
{
|
||||
content_length = atoi(sb->buf + strlen(LENGTH));
|
||||
D_PRINTF(debugfile,
|
||||
"web_request: content-length = %d\n",
|
||||
content_length);
|
||||
}
|
||||
#undef LENGTH
|
||||
|
||||
sb_discardn(ptcx, sb, len);
|
||||
}
|
||||
/* event_stop(ptcx, stats); */
|
||||
return sb;
|
||||
error_out:
|
||||
/* event_stop(ptcx, stats); */
|
||||
D_PRINTF(stderr, "web_request failed: %s\n", strerror(errno));
|
||||
sb_delete(sb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
web_discard(ptcx, cmd, req, user)
|
||||
ptcx_t ptcx;
|
||||
web_command_t *cmd;
|
||||
char *req;
|
||||
web_user_t *user;
|
||||
{
|
||||
socket_buffer *sb;
|
||||
int nread;
|
||||
if ((sb = web_request(ptcx, cmd, req, user)) == NULL)
|
||||
return -1;
|
||||
nread = sb->data;
|
||||
while (sb_read(ptcx, sb) > 0)
|
||||
nread += sb->data;
|
||||
sb_delete(sb);
|
||||
return nread;
|
||||
}
|
||||
|
||||
static int
|
||||
web_login(ptcx, cmd, stats, user)
|
||||
ptcx_t ptcx;
|
||||
web_command_t *cmd;
|
||||
web_stats_t *stats;
|
||||
web_user_t *user;
|
||||
{
|
||||
char buf[256], username[128], passwd[128];
|
||||
int ret = 0;
|
||||
string_list_t *page;
|
||||
/* create login URL: */
|
||||
snprintf(username, sizeof(username), cmd->loginFormat,
|
||||
user->usernum, user->domainnum);
|
||||
snprintf(passwd, sizeof(passwd), cmd->passwdFormat,
|
||||
user->usernum, user->domainnum);
|
||||
snprintf(buf, sizeof(buf), cmd->webLoginFormat,
|
||||
username, passwd);
|
||||
event_start(ptcx, &stats->login);
|
||||
if ((ret = web_discard(ptcx, cmd, buf, user)) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "web_login: discard failed for user %d: %s\n",
|
||||
user->usernum, strerror(errno));
|
||||
/* stats->login.errs++; */
|
||||
goto done;
|
||||
}
|
||||
if (user->cookies == NULL)
|
||||
{
|
||||
D_PRINTF(stderr, "web_login: No cookies for user %d\n",
|
||||
user->usernum);
|
||||
/* stats->login.errs++; */
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
for (page = cmd->webLoginPages; page ; page = page->next)
|
||||
{
|
||||
if (web_discard(ptcx, cmd, page->value, user) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "webmail: Can't get page `%s'\n",
|
||||
buf);
|
||||
/* stats->login.errs++; */
|
||||
ret = -1;
|
||||
/* keep going */
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (ret < 0)
|
||||
stats->login.errs++;
|
||||
event_stop(ptcx, &stats->login);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
web_list_msgs(ptcx, cmd, stats, user, msgs, nmsgs)
|
||||
ptcx_t ptcx;
|
||||
web_command_t *cmd;
|
||||
web_stats_t *stats;
|
||||
web_user_t *user;
|
||||
int *msgs;
|
||||
int nmsgs;
|
||||
{
|
||||
socket_buffer *sb;
|
||||
static char *NEWMSG_PRE1 = "\n<td bgcolor=";
|
||||
static char *NEWMSG_PRE2 = "\n<input type=checkbox name=msg value=\"";
|
||||
static char *NEWMSG_POST = "\"";
|
||||
int msg = 0;
|
||||
int len;
|
||||
|
||||
assert(cmd->webIndex != NULL);
|
||||
if ((sb = web_request(ptcx, cmd, cmd->webIndex, user)) == NULL)
|
||||
{
|
||||
msg = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
while (msg < nmsgs && sb_discard(ptcx, sb, NEWMSG_PRE1) >= 0)
|
||||
{
|
||||
D_PRINTF(debugfile, "web_list_msgs: looking for %d/%d\n",
|
||||
msg, nmsgs);
|
||||
|
||||
if (sb_discard(ptcx, sb, NEWMSG_PRE2) < 0)
|
||||
{
|
||||
D_PRINTF(debugfile,
|
||||
"web_list_msgs: message %d pre-delim: %s\n",
|
||||
msg, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
if ((len = sb_get(ptcx, sb, NEWMSG_POST)) < 0)
|
||||
{
|
||||
D_PRINTF(debugfile,
|
||||
"web_list_msgs: message %d post-delim: %s\n",
|
||||
msg, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
msgs[msg++] = atoi(sb->buf);
|
||||
sb_discardn(ptcx, sb, len);
|
||||
D_PRINTF(debugfile, "web_list_msgs: msg %d = %d\n",
|
||||
msg - 1, msgs[msg-1]);
|
||||
}
|
||||
D_PRINTF(debugfile,
|
||||
"web_list_msgs: skipping to eof after %d messages\n", msg);
|
||||
while (sb_read(ptcx, sb) > 0)
|
||||
;
|
||||
done:
|
||||
if (msg < 0)
|
||||
stats->cmd.errs++;
|
||||
if (sb)
|
||||
sb_delete(sb);
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
D_PRINTF(debugfile, "web_list_msgs: done\n");
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int
|
||||
web_get_msg(ptcx, cmd, stats, user, msg)
|
||||
ptcx_t ptcx;
|
||||
web_command_t *cmd;
|
||||
web_stats_t *stats;
|
||||
web_user_t *user;
|
||||
int msg;
|
||||
{
|
||||
char url[256];
|
||||
int ret;
|
||||
sprintf(url, cmd->webMsgRead, msg);
|
||||
event_start(ptcx, &stats->msgread);
|
||||
if ((ret = web_discard(ptcx, cmd, url, user)) < 0)
|
||||
stats->msgread.errs++;
|
||||
event_stop(ptcx, &stats->msgread);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *
|
||||
doWebmailStart(ptcx, mailcmd, ptimer)
|
||||
ptcx_t ptcx;
|
||||
mail_command_t *mailcmd;
|
||||
cmd_stats_t *ptimer;
|
||||
{
|
||||
web_stats_t *stats = (web_stats_t*)ptimer->data;
|
||||
web_command_t *cmd = (web_command_t*)mailcmd->data;
|
||||
web_user_t *ret = new_web_user(cmd, stats);
|
||||
|
||||
assert(cmd->webIndex != NULL);
|
||||
|
||||
D_PRINTF(debugfile, "doWebmailStart: cmd = %p, user = %p\n",
|
||||
cmd, ret);
|
||||
/* GET login page */
|
||||
if(web_login(ptcx, cmd, stats, ret) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "Login failed for user %d: %s\n",
|
||||
ret->usernum, strerror(errno));
|
||||
delete_web_user(ret);
|
||||
return NULL;
|
||||
}
|
||||
assert(cmd->webIndex != NULL);
|
||||
D_PRINTF(debugfile, "Login done for user %d\n", ret->usernum);
|
||||
return (void*)ret;
|
||||
}
|
||||
|
||||
#define WEB_NEWMSG_MAX 20
|
||||
|
||||
int
|
||||
doWebmailLoop(ptcx, mailcmd, timer, state)
|
||||
ptcx_t ptcx;
|
||||
mail_command_t *mailcmd;
|
||||
cmd_stats_t *timer;
|
||||
void *state;
|
||||
{
|
||||
web_user_t *user = (web_user_t*)state;
|
||||
web_command_t *cmd = (web_command_t*)mailcmd->data;
|
||||
web_stats_t *stats = (web_stats_t*)timer->data;
|
||||
int msgs[WEB_NEWMSG_MAX];
|
||||
int nmsgs;
|
||||
int i;
|
||||
int ndele = 0;
|
||||
|
||||
assert(cmd->webIndex != NULL);
|
||||
D_PRINTF(debugfile, "doWebmailLoop: cmd = %p, user = %p\n",
|
||||
cmd, user);
|
||||
|
||||
if ((nmsgs = web_list_msgs(ptcx, cmd, stats, user, msgs, sizeof(msgs))) < 0)
|
||||
{
|
||||
D_PRINTF(stderr,
|
||||
"doWebmailLoop: list failed for user %d: %s\n",
|
||||
user->usernum, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
D_PRINTF(debugfile, "doWebmailLoop: %d msgs for user %d\n",
|
||||
nmsgs, user->usernum);
|
||||
|
||||
for (i = 0; i < nmsgs; ++i)
|
||||
{
|
||||
if (web_get_msg(ptcx, cmd, stats, user, msgs[i]) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "can't get msg %d for user %d: %s\n",
|
||||
msgs[i], user->usernum, strerror(errno));
|
||||
/* break; */
|
||||
}
|
||||
|
||||
D_PRINTF(debugfile, "doWebmailLoop: downloaded message %d\n",
|
||||
msgs[i]);
|
||||
|
||||
#ifdef MSG_READ_TIME
|
||||
if (cmd->msgReadTime)
|
||||
{
|
||||
int read_time = sample(cmd->msgReadTime);
|
||||
if (read_time > 0)
|
||||
{
|
||||
event_start(ptcx, &timer->idle);
|
||||
MS_idle(ptcx, read_time);
|
||||
event_stop(ptcx, &timer->idle);
|
||||
}
|
||||
}
|
||||
#endif /* MSG_READ_TIME */
|
||||
|
||||
/* maybe mark message for deletion */
|
||||
if (!(cmd->flags & leaveMailOnServer) &&
|
||||
(sample(cmd->leaveMailOnServerDist) == 0))
|
||||
msgs[ndele++] = msgs[i];
|
||||
}
|
||||
/* delete messages (if necessary) */
|
||||
if (ndele > 0)
|
||||
{
|
||||
char buf[8];
|
||||
char deles[8 * WEB_NEWMSG_MAX];
|
||||
char url[512];
|
||||
deles[0] = '\0';
|
||||
for (i = 0; i < ndele; i++)
|
||||
{
|
||||
sprintf(buf, "&msg=%d", msgs[i]);
|
||||
strcat(deles, buf);
|
||||
}
|
||||
D_PRINTF(debugfile, "doWebmailLoop: deleting `%s'\n",
|
||||
deles);
|
||||
snprintf(url, sizeof(url),
|
||||
cmd->webDeleteFormat, deles);
|
||||
event_start(ptcx, &stats->cmd);
|
||||
if (web_discard(ptcx, cmd, url, user) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "doWebmailLoop: delete failed\n");
|
||||
stats->cmd.errs++;
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
return -1;
|
||||
}
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
user->needs_expunge = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
doWebmailEnd(ptcx, mailcmd, ptimer, state)
|
||||
ptcx_t ptcx;
|
||||
mail_command_t *mailcmd;
|
||||
cmd_stats_t *ptimer;
|
||||
void *state;
|
||||
{
|
||||
web_command_t *cmd = (web_command_t*)mailcmd->data;
|
||||
web_stats_t *stats = (web_stats_t*)ptimer->data;
|
||||
web_user_t *user = (web_user_t*)state;
|
||||
|
||||
if (user->needs_expunge)
|
||||
{
|
||||
D_PRINTF(debugfile, "doWebmailEnd: expunge\n");
|
||||
event_start(ptcx, &stats->cmd);
|
||||
if (web_discard(ptcx, cmd, cmd->webExpunge, user) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "doWebmailEnd: expunge failed\n");
|
||||
stats->cmd.errs++;
|
||||
}
|
||||
event_stop(ptcx, &stats->cmd);
|
||||
}
|
||||
|
||||
if (sample(cmd->dropRate))
|
||||
{
|
||||
D_PRINTF(debugfile, "doWebmailEnd: dropped connection\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
event_start(ptcx, &stats->logout);
|
||||
if (web_discard(ptcx, cmd, cmd->webLogout, user) < 0)
|
||||
{
|
||||
D_PRINTF(stderr, "doWebmailEnd: logout failed: %s\n",
|
||||
strerror(errno));
|
||||
stats->logout.errs++;
|
||||
}
|
||||
event_stop(ptcx, &stats->logout);
|
||||
}
|
||||
clear_cookies(user);
|
||||
delete_web_user(user);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
* Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
@@ -38,10 +36,6 @@
|
||||
|
||||
#include "bench.h"
|
||||
#include "http-util.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* flags definitions */
|
||||
#define leaveMailOnServer 0x01
|
||||
|
||||
/*
|
||||
these are protocol dependent timers
|
||||
@@ -87,7 +81,7 @@ typedef struct wmap_command {
|
||||
char * msgdata; /* cache the file in mem */
|
||||
|
||||
/* flag to leave mail on server (dont delete read mail) */
|
||||
int leaveMailOnServerDist;
|
||||
int leaveMailOnServer;
|
||||
|
||||
/* WMAP client http header */
|
||||
char * wmapClientHeader; /* http header for requests w/ %s=referhost %s=host */
|
||||
@@ -147,7 +141,8 @@ int
|
||||
WmapParseStart(pmail_command_t cmd, char *line, param_list_t *defparm)
|
||||
{
|
||||
param_list_t *pp;
|
||||
wmap_command_t *wmap = XCALLOC(wmap_command_t);
|
||||
wmap_command_t *wmap = (wmap_command_t *)mycalloc
|
||||
(sizeof (wmap_command_t));
|
||||
cmd->data = wmap;
|
||||
|
||||
cmd->numLoops = 1; /* default 1 downloads */
|
||||
@@ -265,9 +260,9 @@ WmapParseNameValue(pmail_command_t cmd, char *name, char *tok)
|
||||
if (cmdParseNameValue(cmd, name, tok))/* generic stuff */
|
||||
; /* done */
|
||||
else if (strcmp(name, "server") == 0)
|
||||
wmap->hostInfo.hostName = xstrdup(tok);
|
||||
wmap->hostInfo.hostName = mystrdup(tok);
|
||||
else if (strcmp(name, "loginformat") == 0)
|
||||
wmap->loginFormat = xstrdup(tok);
|
||||
wmap->loginFormat = mystrdup(tok);
|
||||
else if (strcmp(name, "firstlogin") == 0)
|
||||
wmap->loginRange.first = atoi(tok);
|
||||
else if (strcmp(name, "numlogins") == 0)
|
||||
@@ -281,9 +276,9 @@ WmapParseNameValue(pmail_command_t cmd, char *name, char *tok)
|
||||
else if (strcmp(name, "sequentialdomains") == 0)
|
||||
wmap->domainRange.sequential = atoi(tok);
|
||||
else if (strcmp(name, "smtpmailfrom") == 0)
|
||||
wmap->smtpMailFrom = xstrdup(tok);
|
||||
wmap->smtpMailFrom = mystrdup(tok);
|
||||
else if (strcmp(name, "addressformat") == 0)
|
||||
wmap->addressFormat = xstrdup(tok);
|
||||
wmap->addressFormat = mystrdup(tok);
|
||||
else if (strcmp(name, "firstaddress") == 0)
|
||||
wmap->addressRange.first = atoi(tok);
|
||||
else if (strcmp(name, "numaddresses") == 0)
|
||||
@@ -291,7 +286,7 @@ WmapParseNameValue(pmail_command_t cmd, char *name, char *tok)
|
||||
else if (strcmp(name, "sequentialaddresses") == 0)
|
||||
wmap->addressRange.sequential = atoi(tok);
|
||||
else if (strcmp(name, "file") == 0)
|
||||
wmap->filename = xstrdup(tok);
|
||||
wmap->filename = mystrdup(tok);
|
||||
else if (strcmp(name, "numrecips") == 0)
|
||||
wmap->numRecipients = atoi(tok);
|
||||
else if (strcmp(name, "numrecipients") == 0)
|
||||
@@ -299,17 +294,17 @@ WmapParseNameValue(pmail_command_t cmd, char *name, char *tok)
|
||||
else if (strcmp(name, "portnum") == 0)
|
||||
wmap->hostInfo.portNum = atoi(tok);
|
||||
else if (strcmp(name, "passwdformat") == 0)
|
||||
wmap->passwdFormat = xstrdup(tok);
|
||||
wmap->passwdFormat = mystrdup(tok);
|
||||
else if (strcmp(name, "leavemailonserver") == 0)
|
||||
wmap->leaveMailOnServerDist = atoi(tok);
|
||||
wmap->leaveMailOnServer = atoi(tok);
|
||||
else if (strcmp(name, "wmapclientheader") == 0)
|
||||
wmap->wmapClientHeader = xstrdup(tok);
|
||||
wmap->wmapClientHeader = mystrdup(tok);
|
||||
else if (strcmp(name, "wmapbannercmds") == 0)
|
||||
stringListAdd(&wmap->wmapBannerCmds, tok);
|
||||
else if (strcmp(name, "wmaplogincmd") == 0)
|
||||
wmap->wmapLoginCmd = xstrdup(tok);
|
||||
wmap->wmapLoginCmd = mystrdup(tok);
|
||||
else if (strcmp(name, "wmaplogindata") == 0)
|
||||
wmap->wmapLoginData = xstrdup(tok);
|
||||
wmap->wmapLoginData = mystrdup(tok);
|
||||
else if (strcmp(name, "wmapinboxcmds") == 0)
|
||||
stringListAdd(&wmap->wmapInboxCmds, tok);
|
||||
else if (strcmp(name, "wmapcheckcmds") == 0)
|
||||
@@ -333,7 +328,7 @@ WmapStatsInit(mail_command_t *cmd, cmd_stats_t *p, int procNum, int threadNum)
|
||||
assert (NULL != p);
|
||||
|
||||
if (!p->data) { /* create it */
|
||||
p->data = XCALLOC(wmap_stats_t);
|
||||
p->data = mycalloc(sizeof (wmap_stats_t));
|
||||
} else { /* zero it */
|
||||
memset(p->data, 0, sizeof (wmap_stats_t));
|
||||
}
|
||||
@@ -595,15 +590,15 @@ wmapLogin(
|
||||
return -1;
|
||||
}
|
||||
if (me->redirectURL) { /* clean out old values */
|
||||
xfree(me->redirectURL);
|
||||
free(me->redirectURL);
|
||||
me->redirectURL = NULL;
|
||||
}
|
||||
if (me->sessionID) {
|
||||
xfree(me->sessionID);
|
||||
free(me->sessionID);
|
||||
me->sessionID = NULL;
|
||||
}
|
||||
if (me->msgList) {
|
||||
xfree(me->msgList);
|
||||
free(me->msgList);
|
||||
me->msgList = NULL;
|
||||
}
|
||||
|
||||
@@ -621,7 +616,7 @@ wmapLogin(
|
||||
}
|
||||
/* skip host */
|
||||
cp = strchr(cp, '/');
|
||||
me->redirectURL = xstrdup (cp);
|
||||
me->redirectURL = mystrdup (cp);
|
||||
assert (NULL != me->redirectURL);
|
||||
cp = strchr(me->redirectURL, '\r');
|
||||
*cp = '\0';
|
||||
@@ -640,7 +635,7 @@ wmapLogin(
|
||||
return -1;
|
||||
}
|
||||
|
||||
me->sessionID = xstrdup(content);
|
||||
me->sessionID = mystrdup(content);
|
||||
assert (NULL != me->sessionID);
|
||||
|
||||
D_PRINTF(stderr, "sid=%s\n", me->sessionID);
|
||||
@@ -764,7 +759,7 @@ wmapLogout(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t
|
||||
void *
|
||||
doWmapStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
{
|
||||
doWMAP_state_t *me = XCALLOC(doWMAP_state_t);
|
||||
doWMAP_state_t *me = (doWMAP_state_t *)mycalloc (sizeof (doWMAP_state_t));
|
||||
/*wmap_stats_t *stats = (wmap_stats_t *)ptimer->data;*/
|
||||
/*wmap_command_t *wmap = (wmap_command_t *)cmd->data;*/
|
||||
int rc;
|
||||
@@ -839,8 +834,9 @@ GetMessageNumbers (
|
||||
D_PRINTF (stderr, "GetMessageNumber() length=%d\n", me->numMsgs);
|
||||
if (me->numMsgs > 0) {
|
||||
if (me->msgList)
|
||||
xfree (me->msgList);
|
||||
me->msgList = (int *)xcalloc (me->numMsgs * sizeof (int));
|
||||
free (me->msgList);
|
||||
me->msgList = (int *)mycalloc (me->numMsgs * sizeof (int));
|
||||
assert (NULL != me->msgList);
|
||||
}
|
||||
*findStr = MSG_ENTRY; /* now search for each message */
|
||||
} else { /* got a message string */
|
||||
@@ -991,14 +987,14 @@ doWmapExit(ptcx_t ptcx, mail_command_t *cmd, doWMAP_state_t *me)
|
||||
}
|
||||
|
||||
if (me->redirectURL) {
|
||||
xfree(me->redirectURL);
|
||||
free(me->redirectURL);
|
||||
}
|
||||
if (me->sessionID) {
|
||||
xfree(me->sessionID);
|
||||
free(me->sessionID);
|
||||
}
|
||||
if (me->msgList) {
|
||||
xfree (me->msgList);
|
||||
free (me->msgList);
|
||||
}
|
||||
|
||||
xfree(me);
|
||||
myfree(me);
|
||||
}
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Thom O'Connor <thom@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifndef USE_SYSTEM_MALLOC
|
||||
|
||||
/* allocate memory and die if out of memory */
|
||||
void *
|
||||
xalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
#ifdef _DEBUG_xalloc
|
||||
size += 3 * sizeof(int);
|
||||
size += size % sizeof(int);
|
||||
#endif
|
||||
ptr = malloc(size);
|
||||
assert(ptr != NULL);
|
||||
#ifdef _DEBUG_xalloc
|
||||
{
|
||||
char *p = (char*)ptr;
|
||||
*(int*)p = size;
|
||||
*((int*)p + 1) = 0xf00dcafe;
|
||||
*((int*)(p + size - sizeof(int))) = 0xdeadbeef;
|
||||
ptr = (p + 2 * sizeof(int));
|
||||
}
|
||||
#endif
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
xfree(void * ptr)
|
||||
{
|
||||
#ifdef _DEBUG_xalloc
|
||||
char *p = (char*)ptr;
|
||||
int size = *(int*)(p - 2 * sizeof(int));
|
||||
int magic = *(int*)(p - sizeof(int));
|
||||
assert(magic == 0xf00dcafe);
|
||||
magic = *(int*)(p + size - 3 * sizeof(int));
|
||||
assert(magic == 0xdeadbeef);
|
||||
memset(p - 2 * sizeof(int), 0, size);
|
||||
ptr = p - 2 * sizeof(int);
|
||||
#endif
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void *
|
||||
xcalloc(size_t size)
|
||||
{
|
||||
void *ret = xalloc(size);
|
||||
memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
#ifdef _DEBUG_xalloc
|
||||
if (ptr == NULL) {
|
||||
return xalloc(size);
|
||||
} else if (size == 0) {
|
||||
xfree(ptr);
|
||||
return NULL;
|
||||
} else {
|
||||
char *p = (char*)ptr;
|
||||
void *ret = xalloc(size);
|
||||
/* xalloc has already checked the magic */
|
||||
int oldsize = *(int*)(p - 2 * sizeof(int));
|
||||
oldsize -= 3 *sizeof(int);
|
||||
memcpy(ret, ptr, (oldsize>size)?size:oldsize);
|
||||
xfree(ptr);
|
||||
return ret;
|
||||
}
|
||||
#else /* _DEBUG */
|
||||
ptr = realloc(ptr, size);
|
||||
assert(ptr != NULL);
|
||||
return ptr;
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *cp)
|
||||
{
|
||||
char *retcp;
|
||||
int len = strlen(cp);
|
||||
|
||||
retcp = (char *)xalloc(len+1);
|
||||
strcpy(retcp, cp);
|
||||
return retcp;
|
||||
}
|
||||
|
||||
#endif /* USE_SYSTEM_MALLOC */
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Sean O'Rourke <sean@sendmail.com>
|
||||
* Sendmail, Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _xalloc_h
|
||||
#define _xalloc_h
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* xalloc.h -- consolidate memory allocation */
|
||||
|
||||
#define XALLOC(T) (T*)xalloc(sizeof (T))
|
||||
#define XCALLOC(T) (T*)xcalloc(sizeof (T))
|
||||
|
||||
#ifdef USE_SYSTEM_MALLOC
|
||||
#define xalloc(X) malloc(X)
|
||||
#define xcalloc(X) calloc(1, X)
|
||||
#define xrealloc(A, B) realloc(A, B)
|
||||
#define xstrdup(X) strdup(X)
|
||||
#define xfree(X) free(X)
|
||||
#else /* USE_SYSTEM_MALLOC */
|
||||
void *xalloc(size_t size);
|
||||
void *xcalloc(size_t size);
|
||||
void *xrealloc(void *ptr, size_t size);
|
||||
char *xstrdup(const char *cp);
|
||||
void xfree(void *ptr);
|
||||
#endif /* USE_SYSTEM_MALLOC */
|
||||
|
||||
#endif /* _xalloc_h */
|
||||
Reference in New Issue
Block a user