Initial open source checkin of the mstone performance tool

This commit is contained in:
robodan%netscape.com 2000-03-21 23:43:31 +00:00
Родитель e3a117d3c9
Коммит 368d4c9e07
76 изменённых файлов: 17898 добавлений и 0 удалений

24
mstone/Building Normal file
Просмотреть файл

@ -0,0 +1,24 @@
Mstone building instructions
For Unix, just "gmake" one of these
release The usual optimized build
debug Debug build includes some asserts
rpackage Build the release and package it
dpackage Build the debug version and package it
unix_OPT Build a UNIX multi-platform package
unix_DBG Build a UNIX multi-platform debug package
You can build multiple OSes in the same tree. Debug and optimized
builds are kept separately. The unix_??? targets will combine
whatever OSes are present into a multi-architecture package.
For NT, run autobuild.bat. This will build and package both the debug
and optimized versions. Perl must already be built and installed in \.
Helper components
Mstone can build and package perl, gnuplot, and gd. This is currently
being re-worked, but should be fixed soon.

219
mstone/ChangeLog Normal file
Просмотреть файл

@ -0,0 +1,219 @@
Netscape Mailstone - version 4.15 (Dec 10, 1999)
MailStone 4.15: Changes to since version 4.1
- Setup now checks license acceptance and configures a basic setup.
By default, it will also create a user LDIF file with a 'allusers'
account.
- All parameters and and testbed information may now be specified in
the workload files (*.wld). New sections: CONFIG, CLIENT, MONITOR,
PRETEST, and POSTTEST. Command line parameters still override the
files. A complete copy of the configuration is saved in
results/<TIMESTAMP>/all.wld.
- The '*.pl', '*.tbd', and 'config*' files in ./conf/ are depreciated.
These should still work, but the new sections are simpler and more flexible.
- Any CONFIG parameter can now be specified on the command line using
the form: 'PARAMETER=value'. Note that PARAMETER is case
insensitive. No whitespace is allowed before or after the '='.
- The new switch '-l' or CONFIG parameter 'ClientCount' can now
specify the total number of clients. The 'MaxClients' and
'MaxThreads' parameters in each CLIENT section control load
balancing. If the 'processes' and 'threads' parameters are set, then
the load for that CLIENT section will not be adjusted, but will be
taken into account when calculating other CLIENT sections. If just
'processes' is set, then only the thread count will be adjusted. All
hosts in a CLIENT section will run the same number of processes and
threads.
- bin/makeusers.pl now creates users, broadcast account, etc. Numbered passwords
are now suppored. The new user/password format now replaces '%ld' with
the user number to match the rest of mailstone. The ldif/ directory
is obsolete. Run "perl/bin/perl bin/makeusers.pl -h" for usage.
- NT client machines may now be used from a Unix test master. See
conf/sample.wld for configuration details.
- Commands can now be run for a specified block count, error count, or
time (whichever comes first). Set 'maxBlocks' and/or 'maxErrors'.
- Telemetry logging to /var/tmp/mstone-log.pn.tn is now performed when
"telemetry 1" is specified.
- The name used in the "CLIENT" section is now used to match
"HOSTS=..." qualifier. Compatibility with "hostname" is no
longer needed.
- Config values can now use quoted characters such as \n, \r, \t
- Config values can be continued using \ (backslash)
- System configuration information (SYSCONFIG) can now be specified
entirely within a workload file by quoting the newlines.
- Config values get enclosing double-quotes stripped
- Preliminary support for HTTP and WMAP (WebMail) testing.
- New table formats are easier to interpret and allow more protocols.
- The new text format report is easier to machine processes.
- The following command line switches are now obsolete: -f, -g, -e, -p,
and -l. The same functionality can be obtained by
FREQUENCY=<interval>, GNUPLOT=<path>, RSH=<path>, RCP=<path>, and
TEMPDIR=<directory> respectively.
- File backups are now created. When ./process is run multiple
times, the old files are moved to the ./tmp/<TIMESTAMP>/ directory.
- perl has been updated to include full perl5.005_03 install package.
Perl support for each architecture is now under the perl/ directory.
MailStone 4.1: Changes to since version 4.0
- threads are used on all platforms
reduces memory requirements by 10x for large numbers of clients
must run as root for maximum connections per process
- massive internal code and script cleanup / rewrite
performance improvements for socket handling (blocking)
and caching files and name lookups
- filename and path conventions restructuring
'/mailstone' hardwired path no longer required
mailstone/results/index.html (index of test runs)
mailstone/results/<datestamp>/stderr (look here for errors)
mailstone/results/<datestamp>/results.html
mailstone/results/<datestamp>/results.txt
mailstone/results/<datestamp>/work.wld (workload config used)
mailstone/results/<datestamp>/testbed.tbd (testbed used)
mailstone/results/<datestamp>/summary.csv (per client summary)
mailstone/results/<datestamp>/*.gif (graphs)
mailstone/tmp/<datestamp>/*.out (raw results from each client)
mailstone/conf/*.wld (workload file)
mailstone/conf/*.html (machine descriptions for reports)
mailstone/data/*.msg (sample test messages)
- periodic statistics reporting allows for trend analysis of
many variables per protocol.
sampling rate is automatically determined by mailmaster
Can now generate on-the-fly reports for above by running "process"
- The accountFormat directive is now obsolete.
Use loginFormat and addressFormat instead.
- The numAccounts and beginAccounts directives are now obsolete.
Use numLogins, firstLogin, numAddresses, and firstAddress instead.
- The sequentialLogins directive disables random account number selection.
This insures a predictable account sequence.
- The checkMailInterval directive for IMAP is now obsolete.
Use loopDelay instead.
- The directives idleTime, loopDelay, and numLoops now apply to all
protocols. See the manual for how loopDelay and numLoops are used
by each protocol.
- a command directive such as <SMTP> without HOSTS=xxx
will now apply to all clients in the testbed
- <include> directive for workload and testbed files (e.g. for user profile)
- workloads are now passed to 'mailclient' through stdin
no test specific files need to be copied to client machines
more synchonized test startup
- 'setup' script will copy mailclient and test messages (data/*.msg) to
each testbed machine in /var/tmp
- 'cleanup' form of setup will remove mailclient and test messages from
each testbed machine in /var/tmp
- 'checktime' form of setup will (nearly) simultaneously retrieve time from
each client. This lets you easily check for clock problems.
- 'timesync' form of setup will (nearly) simultaneously set time on
each client. This only works on OSs that support setting seconds
through the "date" command. rdate or ntpdate should be used if available.
You must be the root user and be able to rsh as root for timesync to work.
- Improved reports in text and html (formatting and content)
- The text version of the report is now only displayed automatically
if "-v" is given.
- Graphs with more than one protocol will also display a "Total" graph
- The graphs can now be customized for each test (see sample.wld for
the default)
- You can now add graphs (in addition to the default or configured
ones) by using "process timestamp -a conf/moregraph.wld".
- An informative index of test runs is now generated in results/index.html
- The index is updated while the run is in progress to make checking
for errors easier.
- The error log now displays times relative to test start.
- Memory use while processing results has been greatly reduced.
- A summary of the data from each process is now saved in a
Comma-separated-value (CSV) file. results/timestamp/clients.csv
- A summary of the data over time is now saved in a
Comma-separated-value (CSV) file. results/timestamp/protocol-time.csv
- new gnuplot binary included, can output directly to gif format
- read and write performance numbers now reported separately
- new runtime banners and copyrights (ooh boy)
- idleTime option for IMAP fixed, plus now applies to all commands
- blockTime now sets a delay between command blocks
- Process model is as follows
User runs the top-level 'mstone' script
This calls 'conf/testname.pl' with command line arguments
This calls 'mailmaster.pl' with config and command line arguments
mailmaster uses 'rsh' or equivalent to launch mailclients
mailclient runs on each testbed and forks numprocs
each proc spawns numthreads (one per client)
<run tests> (note: results are being sent continuously)
threads send results back through sockets to top mailclient
mailclient forwards results back over stdout via rsh pipe
(for future work - do some data reduction/combining here)
mailmaster directs output to each client-<hostname> file
mailmaster launches report generator
- sample LDIF fragment for a postmaster entry included
Future ideas:
- Data reduction at each testbed client
- test message generator (plain and MIME styles)
- IMAP (and other protocol) scripting
- Implementation of "throttle"
- More graphs for multiple runs
- Script a series of runs varying one parameter at a time
- More protocols (LDAP, disk, DNS, Calendar)
- Option to drop a fraction of connections

222
mstone/INSTALL Normal file
Просмотреть файл

@ -0,0 +1,222 @@
Mailstone 4.15 Quick Installation
This version of Mailstone runs on many current UNIX platforms and NT.
Only a web browser and text editor are needed to view the results and
configure tests.
QUICK INSTALL
-------------
IMPORTANT: If you have an existing mailstone, save a copy of the
mailstone/conf directory to preserve any configuration files you
may want to keep.
Unpack distribution:
tar xzf /tmp/mailstone_OPT.tar.gz
or
gunzip -c /tmp/mailstone_OPT.tar.gz | tar xf -
or
unzip /tmp/mailstone_OPT.zip
cd mailstone
Both the tar.gz file and the zip file are identical. Use whichever is
more convenient for you.
This will create a sub-directory named "mailstone" with files and
directories under that.
cd mailstone
Note that all scripts are expected to be run from the mailstone directory.
Do initial configuration:
Run setup. It will ask you about your system configuration. Fill in
the appropriate values and create the optional user accounts and broadcast
account. When it asks about client machines, enter them seperated by
commas, with no spaces (e.g. host1,host2,host3). If you need to
re-configure, run "setup config".
The machine starting the test may also be a client. For accurate
results, clients should not be run on the test mailserver machine (or
its directory server). If all the client machines are not running
the same operating system version, see "Configuring Client Machines"
below to configure for different OSes.
When the test master is on NT, only the local machine may be a client
and only one process is allowed. You will not be asked about client
machines.
Setup only configures the most important parameters. If you have more
advanced needs, edit conf/general.wld appropriately.
Run setup again. It will now push the necessary files to each client
machine. If there are problems (i.e. with rsh permissions), fix
them and re-run setup until everything works.
Install test accounts:
Setup will create a file called conf/MAILHOST.ldif (where MAILHOST is the
name of your mail server). If you are not using Netscape Messaging
and Directory Servers, then you may have to edit the ldif file or use
alternate means to create the user accounts.
To import these users into Netscape Messaging Server, use "add
entries" from the directory console or use the ldapmodify command line
utility.
Note: imports will go faster if access logging is disabled. For large
user counts (more than 10,000 users), it may be much faster to export
the current database, merge the files together manually, and then
import the new database.
Here is how the ldapmodify supplied with Netscape Messaging Server
would be used.
setenv LD_LIBRARY_PATH /usr/netscape/messaging/lib
cd /usr/netscape/messaging
shared/bin/ldapmodify -h mailhost -a -D 'cn=directory manager' -w d_m_password < conf/MAILHOST.ldif
Check time consistency:
IMPORTANT: The system time on each client machine must be synchronized
within one second of each other for accurate results graphs.
Run "checktime" to see the time on each client. There should not be
more than two seconds difference among the displayed time.
The best way to synchronize clients is use NTP (Network Time Protocol)
or similar protocols (like rdate or timeslave) that have sub second
accuracy.
A simple utility called "timesync" is provide to push the local
system time to all clients. You must be root and have root rsh
permissions to use timesync. Timesync only works on OSs that support
setting seconds using "date MMDDhhmmCCYY.ss". Timesync is only
accurate to a second (at best) and should only be used if better
protocols aren't available.
When running the test master on NT, "checktime" and "timesync" are
never needed (because there is only one client machine). Timesync
will be ignored for NT clients, another method must be used
(e.g. timeserv or Dimension4).
Run tests:
Try it out. Use small process and thread counts until everything is
working.
mstone pop -t 30s
The script will tell you how many processes and threads it is running
on each system and where errors are logged. At the end of the test,
it will print out a URL for the test results and an indication of the
size of the errorlog file (stderr).
The results of the MailStone run will display statistics for each
protocol that was tested. The results are presented in both a HTML
web page and a text file. The text file is simple and uniform, while
the web page is more user readable. The web page has links to the
test configuration files, error log, and the text version.
For long tests run (e.g. 8 hours), the results can be updated while
the test is running by using the "process" utility. Don't run
"process" near the very end of the test.
If a test has to be aborted, then use "process" to generate a report
using the available data.
Customize tests:
Copy and edit the scripts (e.g. "conf/pop.wld") to define new tests.
The CONFIG section specifies all the attributes used in the test.
Other sections specify the protocols to be tested and the parameters
for them.
All switches can be overridden on the command line to facilitate
easier testing. The exact configuration (include command line
overrides) is stored with the results from each test.
Maintenance:
You can run "setup" and any time (except during a test) to update the
files on the client machines.
Use "cleanup" to remove the files created by "setup".
After the test is finished, the directories under "tmp/" can be
compressed or deleted to save space. All the information about a test
run is stored in the "results/" directories.
Configuring client machines:
Edit conf/general.wld to include CLIENT sections for each machines to
use.
You can also specify the OS type for each client machine. Set the
"Arch" parameter in each CLIENT section as appropriate (e.g. SunOS5.6,
Linux2.2_x86, AIX4.2, HP-UXB.11.00, IRIX6.5, OSF1V4.0, WINNT4.0). The
directories under "bin" specify the available OS types.
For NT4.0 clients with a UNIX test master, you will need to configure
"command" and "tempDir" for proper operation. See the "HOSTS=winnt01"
example in conf/sample.wld.
The total number of processes and threads that can be supported on a
client is dependent on the number of commands in the test, the OS, and
available memory. Check the stderr log for messages about not being
able to create processes or threads. Check on the client machines
during the test and make sure they aren't running out of CPU. The
UNIX programs "top" and "vmstat" are good for this. If the client CPU
is more than 75% busy, use more machines.
Also watch out for network saturation. You may have to use machines
with separate networks to the server to reach full server load.
Know problems:
There can be extraneous errors or connections after the specified end
of the test. These are most likely do to stopping the test and should
be ignored.
At the end of the test, all current connections will logout without
any delays. This can cause very high peak loads.
If one process exits early (due to misconfiguration or resource
exhaustion) and the monitoring command did not specify a count (%c),
then the monitoring tasks will be terminated early as well.
Monitoring commands that specify a count (%c), may take longer than
predicted and delay the processing of test results. This is because
vmstat actually delays the requested time plus the time needed to
generate the statistics summary.
If you are doing tests with large thread counts, you may have to run
as root to allow mailclient to raise its resource limits.
The telemetry logging for SMTP, POP3, and IMAP4 is incomplete. Most
commands are captured, but banners and message contents may be missing.
The MaxBlocks parameter gets divided by the total number of processes
before starting each client. This doesn't account for clients that
don't have commands to run.
The HTTP protocol used by WMAP allows connections to be dropped and
re-connected as needed. WMAP logs this as an error and an additional
connect. The error log must be consulted to distinguish another types
of connection errors (timeout or connection refused) from an automatic
re-connect.
The HTTP protocol test is experimental and subject to change.

535
mstone/LICENSE Normal file
Просмотреть файл

@ -0,0 +1,535 @@
MOZILLA PUBLIC LICENSE
Version 1.1
---------------
1. Definitions.
1.0.1. "Commercial Use" means distribution or otherwise making the
Covered Code available to a third party.
1.1. "Contributor" means each entity that creates or contributes to
the creation of Modifications.
1.2. "Contributor Version" means the combination of the Original
Code, prior Modifications used by a Contributor, and the Modifications
made by that particular Contributor.
1.3. "Covered Code" means the Original Code or Modifications or the
combination of the Original Code and Modifications, in each case
including portions thereof.
1.4. "Electronic Distribution Mechanism" means a mechanism generally
accepted in the software development community for the electronic
transfer of data.
1.5. "Executable" means Covered Code in any form other than Source
Code.
1.6. "Initial Developer" means the individual or entity identified
as the Initial Developer in the Source Code notice required by Exhibit
A.
1.7. "Larger Work" means a work which combines Covered Code or
portions thereof with code not governed by the terms of this License.
1.8. "License" means this document.
1.8.1. "Licensable" means having the right to grant, to the maximum
extent possible, whether at the time of the initial grant or
subsequently acquired, any and all of the rights conveyed herein.
1.9. "Modifications" means any addition to or deletion from the
substance or structure of either the Original Code or any previous
Modifications. When Covered Code is released as a series of files, a
Modification is:
A. Any addition to or deletion from the contents of a file
containing Original Code or previous Modifications.
B. Any new file that contains any part of the Original Code or
previous Modifications.
1.10. "Original Code" means Source Code of computer software code
which is described in the Source Code notice required by Exhibit A as
Original Code, and which, at the time of its release under this
License is not already Covered Code governed by this License.
1.10.1. "Patent Claims" means any patent claim(s), now owned or
hereafter acquired, including without limitation, method, process,
and apparatus claims, in any patent Licensable by grantor.
1.11. "Source Code" means the preferred form of the Covered Code for
making modifications to it, including all modules it contains, plus
any associated interface definition files, scripts used to control
compilation and installation of an Executable, or source code
differential comparisons against either the Original Code or another
well known, available Covered Code of the Contributor's choice. The
Source Code can be in a compressed or archival form, provided the
appropriate decompression or de-archiving software is widely available
for no charge.
1.12. "You" (or "Your") means an individual or a legal entity
exercising rights under, and complying with all of the terms of, this
License or a future version of this License issued under Section 6.1.
For legal entities, "You" includes any entity which controls, is
controlled by, or is under common control with You. For purposes of
this definition, "control" means (a) the power, direct or indirect,
to cause the direction or management of such entity, whether by
contract or otherwise, or (b) ownership of more than fifty percent
(50%) of the outstanding shares or beneficial ownership of such
entity.
2. Source Code License.
2.1. The Initial Developer Grant.
The Initial Developer hereby grants You a world-wide, royalty-free,
non-exclusive license, subject to third party intellectual property
claims:
(a) under intellectual property rights (other than patent or
trademark) Licensable by Initial Developer to use, reproduce,
modify, display, perform, sublicense and distribute the Original
Code (or portions thereof) with or without Modifications, and/or
as part of a Larger Work; and
(b) under Patents Claims infringed by the making, using or
selling of Original Code, to make, have made, use, practice,
sell, and offer for sale, and/or otherwise dispose of the
Original Code (or portions thereof).
(c) the licenses granted in this Section 2.1(a) and (b) are
effective on the date Initial Developer first distributes
Original Code under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is
granted: 1) for code that You delete from the Original Code; 2)
separate from the Original Code; or 3) for infringements caused
by: i) the modification of the Original Code or ii) the
combination of the Original Code with other software or devices.
2.2. Contributor Grant.
Subject to third party intellectual property claims, each Contributor
hereby grants You a world-wide, royalty-free, non-exclusive license
(a) under intellectual property rights (other than patent or
trademark) Licensable by Contributor, to use, reproduce, modify,
display, perform, sublicense and distribute the Modifications
created by such Contributor (or portions thereof) either on an
unmodified basis, with other Modifications, as Covered Code
and/or as part of a Larger Work; and
(b) under Patent Claims infringed by the making, using, or
selling of Modifications made by that Contributor either alone
and/or in combination with its Contributor Version (or portions
of such combination), to make, use, sell, offer for sale, have
made, and/or otherwise dispose of: 1) Modifications made by that
Contributor (or portions thereof); and 2) the combination of
Modifications made by that Contributor with its Contributor
Version (or portions of such combination).
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
effective on the date Contributor first makes Commercial Use of
the Covered Code.
(d) Notwithstanding Section 2.2(b) above, no patent license is
granted: 1) for any code that Contributor has deleted from the
Contributor Version; 2) separate from the Contributor Version;
3) for infringements caused by: i) third party modifications of
Contributor Version or ii) the combination of Modifications made
by that Contributor with other software (except as part of the
Contributor Version) or other devices; or 4) under Patent Claims
infringed by Covered Code in the absence of Modifications made by
that Contributor.
3. Distribution Obligations.
3.1. Application of License.
The Modifications which You create or to which You contribute are
governed by the terms of this License, including without limitation
Section 2.2. The Source Code version of Covered Code may be
distributed only under the terms of this License or a future version
of this License released under Section 6.1, and You must include a
copy of this License with every copy of the Source Code You
distribute. You may not offer or impose any terms on any Source Code
version that alters or restricts the applicable version of this
License or the recipients' rights hereunder. However, You may include
an additional document offering the additional rights described in
Section 3.5.
3.2. Availability of Source Code.
Any Modification which You create or to which You contribute must be
made available in Source Code form under the terms of this License
either on the same media as an Executable version or via an accepted
Electronic Distribution Mechanism to anyone to whom you made an
Executable version available; and if made available via Electronic
Distribution Mechanism, must remain available for at least twelve (12)
months after the date it initially became available, or at least six
(6) months after a subsequent version of that particular Modification
has been made available to such recipients. You are responsible for
ensuring that the Source Code version remains available even if the
Electronic Distribution Mechanism is maintained by a third party.
3.3. Description of Modifications.
You must cause all Covered Code to which You contribute to contain a
file documenting the changes You made to create that Covered Code and
the date of any change. You must include a prominent statement that
the Modification is derived, directly or indirectly, from Original
Code provided by the Initial Developer and including the name of the
Initial Developer in (a) the Source Code, and (b) in any notice in an
Executable version or related documentation in which You describe the
origin or ownership of the Covered Code.
3.4. Intellectual Property Matters
(a) Third Party Claims.
If Contributor has knowledge that a license under a third party's
intellectual property rights is required to exercise the rights
granted by such Contributor under Sections 2.1 or 2.2,
Contributor must include a text file with the Source Code
distribution titled "LEGAL" which describes the claim and the
party making the claim in sufficient detail that a recipient will
know whom to contact. If Contributor obtains such knowledge after
the Modification is made available as described in Section 3.2,
Contributor shall promptly modify the LEGAL file in all copies
Contributor makes available thereafter and shall take other steps
(such as notifying appropriate mailing lists or newsgroups)
reasonably calculated to inform those who received the Covered
Code that new knowledge has been obtained.
(b) Contributor APIs.
If Contributor's Modifications include an application programming
interface and Contributor has knowledge of patent licenses which
are reasonably necessary to implement that API, Contributor must
also include this information in the LEGAL file.
(c) Representations.
Contributor represents that, except as disclosed pursuant to
Section 3.4(a) above, Contributor believes that Contributor's
Modifications are Contributor's original creation(s) and/or
Contributor has sufficient rights to grant the rights conveyed by
this License.
3.5. Required Notices.
You must duplicate the notice in Exhibit A in each file of the Source
Code. If it is not possible to put such notice in a particular Source
Code file due to its structure, then You must include such notice in a
location (such as a relevant directory) where a user would be likely
to look for such a notice. If You created one or more Modification(s)
You may add your name as a Contributor to the notice described in
Exhibit A. You must also duplicate this License in any documentation
for the Source Code where You describe recipients' rights or ownership
rights relating to Covered Code. You may choose to offer, and to
charge a fee for, warranty, support, indemnity or liability
obligations to one or more recipients of Covered Code. However, You
may do so only on Your own behalf, and not on behalf of the Initial
Developer or any Contributor. You must make it absolutely clear than
any such warranty, support, indemnity or liability obligation is
offered by You alone, and You hereby agree to indemnify the Initial
Developer and every Contributor for any liability incurred by the
Initial Developer or such Contributor as a result of warranty,
support, indemnity or liability terms You offer.
3.6. Distribution of Executable Versions.
You may distribute Covered Code in Executable form only if the
requirements of Section 3.1-3.5 have been met for that Covered Code,
and if You include a notice stating that the Source Code version of
the Covered Code is available under the terms of this License,
including a description of how and where You have fulfilled the
obligations of Section 3.2. The notice must be conspicuously included
in any notice in an Executable version, related documentation or
collateral in which You describe recipients' rights relating to the
Covered Code. You may distribute the Executable version of Covered
Code or ownership rights under a license of Your choice, which may
contain terms different from this License, provided that You are in
compliance with the terms of this License and that the license for the
Executable version does not attempt to limit or alter the recipient's
rights in the Source Code version from the rights set forth in this
License. If You distribute the Executable version under a different
license You must make it absolutely clear that any terms which differ
from this License are offered by You alone, not by the Initial
Developer or any Contributor. You hereby agree to indemnify the
Initial Developer and every Contributor for any liability incurred by
the Initial Developer or such Contributor as a result of any such
terms You offer.
3.7. Larger Works.
You may create a Larger Work by combining Covered Code with other code
not governed by the terms of this License and distribute the Larger
Work as a single product. In such a case, You must make sure the
requirements of this License are fulfilled for the Covered Code.
4. Inability to Comply Due to Statute or Regulation.
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Code due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description
must be included in the LEGAL file described in Section 3.4 and must
be included with all distributions of the Source Code. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Application of this License.
This License applies to code to which the Initial Developer has
attached the notice in Exhibit A and to related Covered Code.
6. Versions of the License.
6.1. New Versions.
Netscape Communications Corporation ("Netscape") may publish revised
and/or new versions of the License from time to time. Each version
will be given a distinguishing version number.
6.2. Effect of New Versions.
Once Covered Code has been published under a particular version of the
License, You may always continue to use it under the terms of that
version. You may also choose to use such Covered Code under the terms
of any subsequent version of the License published by Netscape. No one
other than Netscape has the right to modify the terms applicable to
Covered Code created under this License.
6.3. Derivative Works.
If You create or use a modified version of this License (which you may
only do in order to apply it to code which is not already Covered Code
governed by this License), You must (a) rename Your license so that
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
"MPL", "NPL" or any confusingly similar phrase do not appear in your
license (except to note that your license differs from this License)
and (b) otherwise make it clear that Your version of the license
contains terms which differ from the Mozilla Public License and
Netscape Public License. (Filling in the name of the Initial
Developer, Original Code or Contributor in the notice described in
Exhibit A shall not of themselves be deemed to be modifications of
this License.)
7. DISCLAIMER OF WARRANTY.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
8. TERMINATION.
8.1. This License and the rights granted hereunder will terminate
automatically if You fail to comply with terms herein and fail to cure
such breach within 30 days of becoming aware of the breach. All
sublicenses to the Covered Code which are properly granted shall
survive any termination of this License. Provisions which, by their
nature, must remain in effect beyond the termination of this License
shall survive.
8.2. If You initiate litigation by asserting a patent infringement
claim (excluding declatory judgment actions) against Initial Developer
or a Contributor (the Initial Developer or Contributor against whom
You file such action is referred to as "Participant") alleging that:
(a) such Participant's Contributor Version directly or indirectly
infringes any patent, then any and all rights granted by such
Participant to You under Sections 2.1 and/or 2.2 of this License
shall, upon 60 days notice from Participant terminate prospectively,
unless if within 60 days after receipt of notice You either: (i)
agree in writing to pay Participant a mutually agreeable reasonable
royalty for Your past and future use of Modifications made by such
Participant, or (ii) withdraw Your litigation claim with respect to
the Contributor Version against such Participant. If within 60 days
of notice, a reasonable royalty and payment arrangement are not
mutually agreed upon in writing by the parties or the litigation claim
is not withdrawn, the rights granted by Participant to You under
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
the 60 day notice period specified above.
(b) any software, hardware, or device, other than such Participant's
Contributor Version, directly or indirectly infringes any patent, then
any rights granted to You by such Participant under Sections 2.1(b)
and 2.2(b) are revoked effective as of the date You first made, used,
sold, distributed, or had made, Modifications made by that
Participant.
8.3. If You assert a patent infringement claim against Participant
alleging that such Participant's Contributor Version directly or
indirectly infringes any patent where such claim is resolved (such as
by license or settlement) prior to the initiation of patent
infringement litigation, then the reasonable value of the licenses
granted by such Participant under Sections 2.1 or 2.2 shall be taken
into account in determining the amount or value of any payment or
license.
8.4. In the event of termination under Sections 8.1 or 8.2 above,
all end user license agreements (excluding distributors and resellers)
which have been validly granted by You or any distributor hereunder
prior to termination shall survive termination.
9. LIMITATION OF LIABILITY.
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
10. U.S. GOVERNMENT END USERS.
The Covered Code is a "commercial item," as that term is defined in
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
software" and "commercial computer software documentation," as such
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
all U.S. Government End Users acquire Covered Code with only those
rights set forth herein.
11. MISCELLANEOUS.
This License represents the complete agreement concerning subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. This License shall be governed by
California law provisions (except to the extent applicable law, if
any, provides otherwise), excluding its conflict-of-law provisions.
With respect to disputes in which at least one party is a citizen of,
or an entity chartered or registered to do business in the United
States of America, any litigation relating to this License shall be
subject to the jurisdiction of the Federal Courts of the Northern
District of California, with venue lying in Santa Clara County,
California, with the losing party responsible for costs, including
without limitation, court costs and reasonable attorneys' fees and
expenses. The application of the United Nations Convention on
Contracts for the International Sale of Goods is expressly excluded.
Any law or regulation which provides that the language of a contract
shall be construed against the drafter shall not apply to this
License.
12. RESPONSIBILITY FOR CLAIMS.
As between Initial Developer and the Contributors, each party is
responsible for claims and damages arising, directly or indirectly,
out of its utilization of rights under this License and You agree to
work with Initial Developer and Contributors to distribute such
responsibility on an equitable basis. Nothing herein is intended or
shall be deemed to constitute any admission of liability.
13. MULTIPLE-LICENSED CODE.
Initial Developer may designate portions of the Covered Code as
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
Developer permits you to utilize portions of the Covered Code under
Your choice of the NPL or the alternative licenses, if any, specified
by the Initial Developer in the file described in Exhibit A.
EXHIBIT A-Netscape Public License.
"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 code, 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@netscape.com>
Jim Salter <jsalter@netscape.com>
Mike Blakely, David Shak, Brain Williams
Alternatively, the contents of this file may be used under the
terms of the GNU General Public license Version 2 or later
(the "GPL"), in which case the provisions of 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 License."
----------------------------------------------------------------------
AMENDMENTS
The Netscape Public License Version 1.1 ("NPL") consists of the
Mozilla Public License Version 1.1 with the following Amendments,
including Exhibit A-Netscape Public License. Files identified with
"Exhibit A-Netscape Public License" are governed by the Netscape
Public License Version 1.1.
Additional Terms applicable to the Netscape Public License.
I. Effect.
These additional terms described in this Netscape Public
License -- Amendments shall apply to the Mozilla Communicator
client code and to all Covered Code under this License.
II. "Netscape's Branded Code" means Covered Code that Netscape
distributes and/or permits others to distribute under one or more
trademark(s) which are controlled by Netscape but which are not
licensed for use under this License.
III. Netscape and logo.
This License does not grant any rights to use the trademarks
"Netscape", the "Netscape N and horizon" logo or the "Netscape
lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript",
"Smart Browsing" even if such marks are included in the Original
Code or Modifications.
IV. Inability to Comply Due to Contractual Obligation.
Prior to licensing the Original Code under this License, Netscape
has licensed third party code for use in Netscape's Branded Code.
To the extent that Netscape is limited contractually from making
such third party code available under this License, Netscape may
choose to reintegrate such code into Covered Code without being
required to distribute such code in Source Code form, even if
such code would otherwise be considered "Modifications" under
this License.
V. Use of Modifications and Covered Code by Initial Developer.
V.1. In General.
The obligations of Section 3 apply to Netscape, except to
the extent specified in this Amendment, Section V.2 and V.3.
V.2. Other Products.
Netscape may include Covered Code in products other than the
Netscape's Branded Code which are released by Netscape
during the two (2) years following the release date of the
Original Code, without such additional products becoming
subject to the terms of this License, and may license such
additional products on different terms from those contained
in this License.
V.3. Alternative Licensing.
Netscape may license the Source Code of Netscape's Branded
Code, including Modifications incorporated therein, without
such Netscape Branded Code becoming subject to the terms of
this License, and may license such Netscape Branded Code on
different terms from those contained in this License.
VI. Litigation.
Notwithstanding the limitations of Section 11 above, the
provisions regarding litigation in Section 11(a), (b) and (c) of
the License shall apply to all disputes relating to this License.

164
mstone/Makefile Normal file
Просмотреть файл

@ -0,0 +1,164 @@
# Makefile for mailstone
# use gmake
OS_CONFIG := $(shell ./nsarch)
OBJDIR=$(OS_CONFIG)$(OBJDIR_TAG).OBJ
BUILDDIR=build/$(OBJDIR)
PKGDIR=build/package/$(OBJDIR)/mailstone
CP := cp -p
STRIP := strip
ECHO := /bin/echo
all:: usage
usage::
@$(ECHO) "gmake [ release | rpackage | debug | dpackage ]"
@$(ECHO) " [ DIST=/m/dist/mailstone/1999xxxx dist ]"
@$(ECHO) " [ unix_DBG | unix_OPT ]"
targets:: mailclient
mailclient::
@$(ECHO) "\n===== [`date`] making OS_CONFIG=$(OS_CONFIG) BUILD_VARIANT=$(BUILD_VARIANT)\n"
(cd src; $(MAKE) BUILD_VARIANT=$(BUILD_VARIANT) OBJDIR=../$(BUILDDIR) PKGDIR=../$(PKGDIR) all)
GDFILES = gd.txt gd.html gd.h libgd.* demoin.gif gddemo giftogd webgif
GNUPLOTFILES = gnuplot gnuplot_x11 gnuplot.1 gnuplot.gih Copyright
# Create packaging binary directories
# Note: dont make gd or gnuplot here. For multi-OS, they are links
mkpkgdirs::
[ -d $(PKGDIR)/bin ] || mkdir -p $(PKGDIR)/bin
[ -d $(PKGDIR)/conf ] || mkdir -p $(PKGDIR)/conf
[ -d $(PKGDIR)/data ] || mkdir -p $(PKGDIR)/data
# operating system independent share-files (at least for Unix)
pkg-share-files:: mkpkgdirs
@$(ECHO) "\n===== [`date`] making package share-files...\n"
$(CP) mstone setup process $(PKGDIR)
(cd $(PKGDIR); [ ! -f cleanup ] || rm -f cleanup; ln -s setup cleanup)
(cd $(PKGDIR); [ ! -f checktime ] || rm -f checktime; ln -s setup checktime)
(cd $(PKGDIR); [ ! -f timesync ] || rm -f timesync; ln -s setup timesync)
$(CP) nsarch bin/*.pl $(PKGDIR)/bin
$(CP) conf/*.wld conf/*.html $(PKGDIR)/conf
$(CP) data/*.msg $(PKGDIR)/data
#$(CP) doc/MailStone.html $(PKGDIR)/doc
$(CP) INSTALL $(PKGDIR)
$(CP) README $(PKGDIR)
$(CP) ChangeLog $(PKGDIR)
$(CP) LICENSE $(PKGDIR)
@$(ECHO) "\n===== [`date`] making package share-files done.\n"
# split out OS specific file so that combined packaging possible (set PKGDIR)
###pkg-arch-files:: mkpkgdirs $(BUILDDIR)/mailclient $(BUILDDIR)/gd/libgd.a \
### $(BUILDDIR)/gnuplot/gnuplot
pkg-arch-files:: mkpkgdirs $(BUILDDIR)/mailclient
@$(ECHO) "\n===== [`date`] making package arch-files...\n"
[ -d $(PKGDIR)/gd ] || mkdir -p $(PKGDIR)/gd
### [ -d $(PKGDIR)/gnuplot ] || mkdir -p $(PKGDIR)/gnuplot
$(CP) $(BUILDDIR)/mailclient $(PKGDIR)/bin
### $(CP) $(addprefix $(BUILDDIR)/gd/, $(GDFILES)) $(PKGDIR)/gd
### $(CP) $(addprefix $(BUILDDIR)/gnuplot/, $(GNUPLOTFILES)) $(PKGDIR)/gnuplot
ifeq ($(BUILD_VARIANT),release)
-$(STRIP) $(PKGDIR)/bin/mailclient
### -$(STRIP) $(PKGDIR)/gd/webgif $(PKGDIR)/gd/giftogd $(PKGDIR)/gd/gddemo
### -$(STRIP) $(PKGDIR)/gnuplot/gnuplot $(PKGDIR)/gnuplot/gnuplot_x11
endif
@$(ECHO) "\n===== [`date`] making package arch-files done.\n"
pkg-perl-files:: $(BUILDDIR)/perl/perl
@$(ECHO) "\n===== [`date`] making package perl-files...\n"
@[ -d $(PKGDIR)/perl ] || mkdir -p $(PKGDIR)/perl
(cd src; $(MAKE) BUILD_VARIANT=$(BUILD_VARIANT) OBJDIR=../$(BUILDDIR) PKGDIR=../$(PKGDIR) package-perl)
find $(PKGDIR)/perl/lib -name .packlist -exec rm {} \; -print
ifeq ($(BUILD_VARIANT),release)
-$(STRIP) $(PKGDIR)/perl/bin/perl
-$(STRIP) $(PKGDIR)/perl/bin/a2p
endif
@$(ECHO) "\n===== [`date`] making package perl-files done.\n"
###pkg:: targets pkg-share-files pkg-arch-files pkg-perl-files
pkg:: targets pkg-share-files pkg-arch-files
@$(ECHO) "\n===== [`date`] making os package file...\n"
-rm -f ./build/mailstone-4.1-$(OS_CONFIG)$(OBJDIR_TAG).tar.gz
(cd $(dir $(PKGDIR)) && \
tar cf - . | gzip > ../../mailstone-4.1-$(OS_CONFIG)$(OBJDIR_TAG).tar.gz)
@$(ECHO) "\n===== [`date`] making os package file done.\n"
# Install and re-map short Linux name to standard Netscape convention
dist::
@[ "$(DIST)" != "" ] || ($(MAKE) usage && /bin/false)
@[ ! -d "$(DIST)" ] || ($(ECHO) "Error: $(DIST) already exists" && \
$(MAKE) usage && /bin/false)
mkdir -p $(DIST)
cd build/package; $(CP) -R * $(DIST)
cd $(DIST); for l in Linux*_???.OBJ ; do \
nn=`echo $$l | sed -e 's/_OPT/_glibc_PTH_OPT/' | sed -e 's/_DBG/_glibc_PTH_DBG/'`; \
ln -s $$l $$nn; done
# Generate a combined build for every Unix OS that is already built and packaged
# NT has to be done seperately because it has different file names
# We have to nuke some old parts, because permissions wont allow overwrites
# Finally, dont ship perl development headers and libraries
unix_DBG unix_OPT::
@$(ECHO) "\n===== [`date`] making unified packaging for $@...\n"
$(MAKE) OBJDIR=$@.OBJ pkg-share-files
(\
pkgdir=./build/package/$@.OBJ/mailstone; export pkgdir; \
oslist="$(notdir $(shell ls -d build/[A-V]*$(subst unix,,$@.OBJ)))"; \
goodperl=`ls -d ./build/package/*/mailstone/perl/man/man1 | head -1 | sed -e 's:perl/man/man1::'`; \
rm -rf $${pkgdir}/perl/lib/*; \
$(ECHO) "\n===== [`date`] making shared perl packaging from $$goodperl...\n"; \
(cd $${goodperl} && tar cf - perl/man) | (cd $${pkgdir} && tar xf -); \
cp $${goodperl}/perl/Artistic $${pkgdir}/perl; \
for obj in $$oslist ; do \
arch=`echo $${obj} | sed -e 's/_OPT.OBJ//' | sed -e 's/_DBG.OBJ//'` ;\
perlarchdir=$${pkgdir}/perl/arch/$${arch}; export perlarchdir; \
$(MAKE) PKGDIR=$${pkgdir}/bin/$${arch} BUILDDIR=./build/$${obj} pkg-arch-files ; \
$(ECHO) "\n===== [`date`] making arch perl packaging $${perlarchdir}...\n"; \
(cd ./build/package/$${obj}/mailstone && tar cf - perl/lib) | (cd $${pkgdir} && tar xf -); \
[ -d $${perlarchdir} ] || mkdir -p $${perlarchdir}; \
(cd ./build/package/$${obj}/mailstone/perl/bin && tar cf - .) | (cd $${perlarchdir} && tar xf -); \
done; \
rm -rf $${pkgdir}/perl/lib/5.00503/*/CORE/; \
: )
@$(ECHO) "\n===== [`date`] making unified compressed tar file...\n"
-rm -f ./build/mailstone-4.1-$@.tar.gz
(cd ./build/package/$@.OBJ && tar cf - . | gzip > ../../mailstone-4.1-$@.tar.gz)
@$(ECHO) "\n===== [`date`] making unified packaging for $@ done.\n"
release::
@$(ECHO) "\n===== [`date`] making release build...\n"
$(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT targets
@$(ECHO) "\n===== [`date`] making release build done.\n"
rpackage:: release
@$(ECHO) "\n===== [`date`] making release package...\n"
$(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT pkg
@$(ECHO) "\n===== [`date`] making release package done.\n"
debug::
@$(ECHO) "\n===== [`date`] making debug build...\n"
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG targets
@$(ECHO) "\n===== [`date`] making debug build done.\n"
dpackage:: debug
@$(ECHO) "\n===== [`date`] making debug package...\n"
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG pkg
@$(ECHO) "\n===== [`date`] making debug package done.\n"
cleanvariant::
(cd src; $(MAKE) OBJDIR=../build/$(OBJDIR) clean)
rm -rf $(PKGDIR)
clean::
$(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT cleanvariant
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG cleanvariant
distcleanvariant::
(cd src; $(MAKE) OBJDIR=../build/$(OBJDIR) distclean)
rm -rf $(BUILDDIR) $(PKGDIR)
distclean:: clean
$(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT distcleanvariant
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG distcleanvariant

75
mstone/README Normal file
Просмотреть файл

@ -0,0 +1,75 @@
MAILSTONE 4.15
Mailstone is a mail server performance testing tool designed to
simulate the different types and volume of mail traffic a mail server
would experience during a peak activity period.
A quick installation guide is available in INSTALL.
The full Mailstone 4.15 user manual is available at
http://developer.iplanet.com/docs/manuals/messaging.html
Testing strategy
----------------
Mailstone is capable of opening SMTP, POP3, IMAP4, and other protocol
connections to mail servers. The number and type of connections made
to the mail server is based on a weighted command list which provides
the ability to test mail server implementation requirements.
A series of perl script allow you to setup client machines, run tests,
and then cleanup client machine files. Each client machine has a copy
of the mailclient program and SMTP message files. When the test is
run, the mailclient is started with the proper command line and work load.
After experimenting with MailStone loads, you will notice that there
are a few factors that can distort server the byte and message
throughput. You will find that the server byte throughput is related
to the average SMTP message (file) size. Also, server throughput, in
bytes and messages, is affected by larger than normal POP3/IMAP4
mailboxes. So it is important to approach the MailStone command
configuration with data collected from existing mail server
implementations, for example, a customer might say "during our peak
activity in the morning, we handle up to two thousand employees
sending an average of 5 messages of 20K average size and receiving 25
messages of same size". With input like this, you can begin tuning
MailStone to generate relevant data.
There are two important things to consider when reviewing the results of
MailStone performance analysis: Was the test run on target for
simulating the type and volume of mail traffic; and did the server, both
software and machine, handle the load within an acceptable margin?
With this information, it can be determined: whether enough SMTP
connections were made to the server during the run, and how many
messages were downloaded over how many POP3/IMAP4 connections. If the
number of SMTP connections is not in the acceptable range, then
consider adding more client processes/machines or checking the server
performance during the run. The message/connection ratio for
POP3/IMAP4 should be checked for soundness, and adjustments should be
made to the mailboxes before running the next test.
Monitoring the server performance during test runs is crucial in
understanding the results. If the number of client connections is not
being achieved and the server cpu usage and process run queue is not
settling down after the initial spike, then modifications to the server
architecture could be in order.
The analysis of MailStone results is an iterative process of client
(MailStone client) and server tuning. The bottom line is to determine
whether the messaging solution can handle the type of load expected in
an acceptable manner.
Server Log Tuning
-----------------
The Messaging and Directory server ship with access logging enabled by
default. This gives the most information about what is going on in
the system, but can reduce performance. You should test the way the
system will be run.
Noticeable performance increases are often obtained by disabling access
logging on the directory server and by reducing the logging level of
the messaging servers from "Notice" to "Warning".

196
mstone/ToDo Normal file
Просмотреть файл

@ -0,0 +1,196 @@
Mstone TODO List
Updated:
3-20-2000 Dan Christian
======================================================================
Minor improvements
IncludeOnce
Variant on the current include that will include the specified
file only once. This will allow test workloads to be used either as a
stand alone test (which requires including general.wld) or as part of
another test (which has allready included general.wld).
IMAP delete without reading
Just get the message list and delete everything. This could
be the fastest way to drain out the store.
Display MIN/MAX or standard deviation on graphs
Gnuplot can do data points with error bars. You could either
use MIN/MAX or the standard deviation for the error bars. There are
issues with calculating the standard deviation numbers throughout the
graph that need to be addressed.
Statistics reset
At least the MIN and MAX statistics could be easily reset
during the test (after ramp up). This keeps the transients during
startup and shutdown from dominating these numbers. The standard
deviation statistics are much trickier to reset during the run. It
may be better to isolate sections in post processing.
Perl web server
Sometimes it would be nice to include our own web server to
provide the results (instead of using file: URLs). This would also be
a gateway to form based test configuration editing and allow results
to be interactively updated during tests. Perl with a socket library
could handle this without too much trouble.
Dynamic test loading
Finalize an API for dynamically loading tests. This would
allow tests to be added or updated separately from the core
functionality. This may be needed for some types of security testing.
Link graphs to the results tables
There are already tags by each graph. You should be able to
link the appropriate results table entry to each graph. This sort of
tricky since graphs often combine multiple entries.
Show statistics for every block
Statistics are actually kept for every block in every thread.
There should be a way to view information at this detail.
Man pages
The online docs are nice, but good 'ol man pages would be
great in a different way.
Reduce namespace polution
Scripts names like setup and cleanup are too general. They
should be part of the main 'mstone' script (e.g. mstone setup).
Examples of script series
Include example scripts to run entire series of tests in a
sane way.
Reconnect timer
Protocols based on HTTP (e.g. WMAP) may re-connect during a
session. Currently this is logged as a connect error and then another
connect in order to get the current connection graph right. There
should be a separate reconnect timer that the connection count graph
knows about.
Fix FORMAT clash
At the start of a test, each client process outputs the
information needed to report all its protocols. When there are
multiple processes on one client, these FORMAT lines can intermix and
cause parsing errors.
Set connection drop rate
Drop some percentage of the connections without a proper
shutdown. This tests how well a server can detect and recover from
hard disconnects.
Improve randomness
The way that we generate random numbers in a range may be not
generate the proper randomness. We are using lrand48()%range we
should use (lrand48/RAND_RANGE)*range. There are some end conditions
that need to be thought about. All of this is in the sequence code;
one change should fix (or break :) everything.
Also, we may be generating numbers that are never used. This
may be costly, and can create holes in the proper sequence.
Improve printing
The color graphs are great on screen, but tend to print
poorly. Either we need a better way to generate a printable version
(maybe through a CGI button), or the seperate protocols need to be
printed individually. Also, Communicator does a lousy job of keeping
title with tables or graphs. Hopefully, Mozilla will do better.
======================================================================
Whole new protocol tests:
ICQ
Test high volume instant messaging. Very useful for the
bridges and gateways that people are considering using.
WAP
WAP is the emerging standard for mobile phones.
WCAP
Web based calendar services
LDAP
Use the LDAP SDK to do basic LDAP testing. The SDK probably
isn't fast enough to call this a real performance test, but you can at
least test performance degredation due to load from a real application
(like a mail server).
DNS
Mail servers use DNS a lot. You should at least be able to
see if performance is degrading due to load.
Disk/filesystem
Test read, write, sync, link, un-link, and append performance under
multiple threads.
Cert servers
Test certificate authenticity checking performance
======================================================================
Possible dummy servers:
SMTP
Receive mail via SMTP and ignore it. Usefull for SMTP relay
testing.
DNS
Simulate slow DNS server lookups. Usefull for SMTP relay testing.
======================================================================
Major changes
Throttling
Monitor and control transaction rates so that specific load
levels can be easily specified. The rates should be able to vary to
simulate peek hour usage and disconnect-restore.
NSPR threading
Use NSPR for threading and sockets. This may allow other OSes
to be used as clients. This might be easy, since mstone does not need
any locking, just simple thread creation and harvesting. NSPR
argument parsing and hashes may also be useful.
SSL
Support SSL on the protocols that allow it. May require NSPR.
Line speed emulation
Simulate the variable delays and limited throughput of dial up
connections.
Scripting
Allow more detailed control of protocol tests. It looks
difficult to make this scalable and fast.
Combined tests
Deliver mail over SMTP and then see when it arrives using IMAP.

0
mstone/autobuild.bat Executable file
Просмотреть файл

838
mstone/bin/args.pl Normal file
Просмотреть файл

@ -0,0 +1,838 @@
# 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): 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.
#####################################################
# This file does argument processing, file IO, and other utility routines
# Where the online docs live
#$mailstoneURL =
# "http://home.netscape.com/eng/server/messaging/4.1/mailston/stone.htm";
$mailstoneURL =
"http://developer.iplanet.com/docs/manuals/messaging.html";
#$mailstoneURL =
# "http://docs.iplanet.com/docs/manuals/messaging/nms415/mailstone/stone.htm"
# Subdirs for results (each under a timestamp dir). Should just hardwire.
$tmpbase = "tmp";
$resultbase = "results";
# This holds everything about the test and system configuration
@workload = ();
# Setup the special CONFIG section
$params{"sectionTitle"} = "CONFIG";
$params{"sectionParams"} = "";
$params{"lineList"} = ();
push @workload, \%params;
# Get the lists discribing the data we process
do 'protoconf.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: $!";
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 statement
if (m/^<include\s+(\S+)\s*>/io) {
($params{DEBUG})
&& print "readWorkloadFile include $1 from $filename.\n";
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 = "$1$level";
open($fh, "<$1") ||
open($fh, "gunzip -c $1.gz |") ||
die "readWorkloadFile Couldn't open testbed file $1: $!";
$filename = $1; # 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"
unless($params{RSH});
# Set default remote copy
$params{RCP} = "/usr/bin/rcp"
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;

236
mstone/bin/genplot.pl Normal file
Просмотреть файл

@ -0,0 +1,236 @@
# 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): 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.
#####################################################
# This file deals with the graphs data only
# Interfaces to gnuplot to generate gifs for HTML inclusion.
# sub function to write data files, fire off gnuscript, and clean up
# Uses global startTime and endTime figured above
# genPlot counterName title label \@protocols \@variables
sub genPlot {
my $name = shift;
my $title = shift;
my $label = shift;
my $protos = shift || die "genPlot: '$name' missing protocols";
my $f = shift;
my $vars = shift || die "genPlot: '$name' missing vars";
my $runlist = "";
my $totPoints = 0;
my $totProtos = 0;
my @realProtos;
my @goodProtos;
# user fewer data points than pixels to look good.
# on 640x480 gif, the graph is about 579x408
my $maxData = int (($params{CHARTWIDTH}-60) * 0.9);
my $averageCnt = int (($endTime - $startTime + ($maxData - 1))/$maxData);
if ($averageCnt < 1) { $averageCnt = 1; } # must be a positive int
($params{DEBUG}) && print "$name: averageCnt=$averageCnt vars = @$vars \n";
foreach $p (@$protos) { # First see if there is anything to graph
($p =~ /^Total$/o) && next; # derived if needed
my $pPoints = 0;
my $gp = $graphs{$p};
ALLVAR: foreach $vm (@$vars) {
my $vp = ($f) ? $gp->{$vm}->{$f} : $gp->{$vm};
unless (($vp) && (scalar %$vp)) {
#print "genplot Checking: $p $vm $f => NO\n";
next;
}
#print "genplot Checking: $p $vm $f => ";
foreach $time (keys %$vp) {
next unless ($vp->{$time} != 0);
$totPoints++;
$pPoints++;
#print "VALUES\n";
last ALLVAR;
}
#print "nothing\n"
}
if ($pPoints > 0) { # count how many protocols have non 0
$totProtos++;
push @goodProtos, $p;
}
}
($params{DEBUG}) && print "\tprotocols: @goodProtos\n";
if ($totPoints == 0) { # nothing in any protocol
print "No data for graph '$name', variables '@$vars'\n";
return 0;
}
foreach $p (@$protos) {
unlink ("$tmpdir/$name.$p"); # remove any previous runs
(($p =~ /^Total$/o) && ($totProtos <= 1))
&& next; # skip Totally if only 1 protocol plus total
($p !~ /^Total$/o) && push @realProtos, $p; # everything but Total
# if ($p =~ /^Total$/o) { # move from last to first
# $runlist = "\'$name.$p\' with lines, " . $runlist;
# next;
# }
$runlist .= ", " if ($runlist); # later ones
$runlist .= "\'$name.$p\' with lines";
}
$totPoints = 0;
foreach $p (@realProtos) { # create the plot data files
open(DATA, ">$tmpdir/$name.$p") ||
die "Can't open $tmpdir/$name.$p:$!";
my $gp = $graphs{$p};
my $n = 0;
my $s = 0.0;
my $sTime = 0.0;
my $vp = ($f) ? $gp->{$vars->[0]}->{$f} : $gp->{$vars->[0]};
# foreach $time (sort numeric keys %$vp) {
for (my $tm = $startTime; $tm <= $endTime; $tm++) {
my $v = 0.0;
foreach $vm (@$vars) {
$vp = ($f) ? $gp->{$vm}->{$f} : $gp->{$vm};
$totPoints++;
# due to optimization in updateDelta,
# 0 entries are undefined (also avoids warning)
$v += ($vp->{$tm}) ? $vp->{$tm} : 0;
# if ($vp->{$tm} < 0) {
# print $name, ": proto=", $p, " var=", $vm,
# " value=", $vp->{$tm}, "\n";
# }
}
$s += $v;
$n += 1;
if ($n == 1) { # NOTE: shifts left in sliding window
$sTime = $tm-$startTime;
}
if ($n >= $averageCnt) {
printf (DATA "%d %f\n", $sTime * $timeStep, $s/$n);
$n = 0;
$s = 0.0;
}
}
if ($n > 0) { # handle end case
printf (DATA "%d %f\n", $sTime * $timeStep, $s/$n);
}
close(DATA);
}
#($params{DEBUG}) && print "\tpoints: $totPoints\n";
# need to handle "Total" case
# read the other files and write out the sum
# FIX: total my be mis-aligned with data
if (($#$protos > $#realProtos) && ($totProtos > 1)) {
unlink ("$tmpdir/$name.Total");
open(DATA, ">$tmpdir/$name.Total") ||
die "Can't open $tmpdir/$name.Total:$!";
foreach $r (@goodProtos) { # get file handles
open($r, "$tmpdir/$name.$r")
|| die "Couldn't open $tmpdir/$name.$r: $!";
}
# ASSUMES files are identical in order
my $first = shift @goodProtos;
# print "First protocol: $first Rest: @realProtos\n";
while (<$first>) {
my ($t, $s) = split ' ', $_;
foreach $r (@goodProtos) { # get file handles
$l = <$r>;
if ($l) {
my ($tt, $v) = split ' ', $l;
$t = $tt unless ($t); # in case first proto missing time
$s += $v;
}
}
printf (DATA "%d %f\n", $t, $s);
}
foreach $r (@goodProtos) { close($r); }
close (DATA);
}
# Create a script to feed to gnuplot, which creates a .gif graph.
$runTime = ($endTime - $startTime + 1) * $timeStep;
unlink("$tmpdir/$name.gpt");
open(SCRIPT, ">$tmpdir/$name.gpt")
|| die "Can't open $tmpdir/$name.gpt:$!";
$gnuplot = $params{GNUPLOT};
if ($gnuplot !~ /^\//) { # if not absolute, adjust for cd $tmpbase
$gnuplot = "../../$gnuplot"; # ASSUME $tmpbase is single dir
}
#print "gnuplot is $gnuplot $params{GNUPLOT}\n";
my $varstring = ""; # create display version of names
foreach $t (@$vars) {
$varstring .= ", " if ($varstring);
$varstring .= ($timerNames{$t}) ? $timerNames{$t} : $t;
}
print SCRIPT<<"!GROK!THIS!";
set terminal gif small size $params{CHARTWIDTH},$params{CHARTHEIGHT}
set output "../../$resultdir/$name.gif" # ASSUME $tmpbase is single dir
set autoscale
set xlabel "Test time (seconds)"
set ylabel "$label"
set title "$title ($varstring) -- $params{TSTAMP}"
plot [0:$runTime] $runlist
!GROK!THIS!
close(SCRIPT);
# run script from tmpbase to clean up line labeling
# my $olddir=getcwd();
chdir $tmpdir;
system (split (/\s/, $gnuplot), "$name.gpt");
chdir "../..";
# chdir $olddir;
unless ($params{DEBUG}) {
# cleanup the plot data (or leave around for debugging)
foreach $p (@$protos) {
unlink("$tmpdir/$name.$p");
}
unlink("$tmpdir/$name.gpt");
}
return 1;
}
return 1;

576
mstone/bin/mailmaster.pl Executable file
Просмотреть файл

@ -0,0 +1,576 @@
#!/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
# 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): Dan Christian <robodan@netscape.com>
# Marcel DePaolis <marcel@netcape.com>
# Mike Blakely
#
# 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.
#####################################################
# see setup.pl for full usage
# mailmaster [-d] [-c <config file>] ...
# This script reads in the client configuration files and will
# fork children to rsh the mailclient process on network clients,
# each child will write test results to /mailstone directory before
# dying. The parent will the read and combine the results.
#
# Make sure the user running this script has rsh privilege across
# all client machines
print "Netscape Mailstone version 4.2\n";
print "Copyright (c) Netscape Communications Corp. 1997-2000\n";
# this parses the command line and config file
do 'args.pl'|| die "$@\n";
parseArgs(); # parse command line
{ # get unique date string
my ($sec, $min, $hour, $mday, $mon, $year) = localtime;
my $tstamp = sprintf ("%04d%02d%02d.%02d%02d",
1900+$year, 1+$mon, $mday, $hour, $min);
if ( -d "$resultbase/$tstamp") { # check for runs within a minute
my $tail = 'a';
while ( -d "$resultbase/$tstamp$tail" ) { $tail++; }
$tstamp .= $tail;
}
$params{TSTAMP} = $tstamp;
}
$resultdir = "$resultbase/$params{TSTAMP}";
$tmpdir = "$tmpbase/$params{TSTAMP}";
$resultstxt = "$resultdir/results.txt";
$resultshtml = "$resultdir/results.html";
mkdir ("$resultbase", 0775);
mkdir ("$tmpbase", 0775);
mkdir ("$resultdir", 0775);
mkdir ("$tmpdir", 0775);
# Make sure we have everything
die "Must specify the test time" unless $params{TIME};
die "Must specify a workload file" unless $params{WORKLOAD};
if ($params{TESTBED}) { # BACK COMPATIBILITY
readTestbedFile ($params{TESTBED}) || die "Error reading testbed: $@\n";
}
$testsecs = figureTimeSeconds ($params{TIME}, "seconds");
# figure out the processes and thread, given the desired number
# takes into account all the constraints. todo can be a float.
sub figurePT {
my $sec = shift;
my $todo = shift;
my $p = 1; # first guess
my $t = 1;
my $start = 1; # initial process guess
my $end = 250; # highest process guess
if ($todo < 1) { # mark this client as inactive
$sec->{PROCESSES} = 0;
$sec->{THREADS} = 0;
return 0;
}
if (($section->{MAXCLIENTS}) && ($todo > $section->{MAXCLIENTS})) {
$todo = $section->{MAXCLIENTS}; # trim to max client per host
}
if ($section->{PROCESSES}) { # they set this part already
$start = int ($section->{PROCESSES});
$end = $start;
$p = $start;
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
print "Using specified $p processes for clients $slist\n";
}
$end = int ($section->{MAXPROCESSES})
if ($section->{MAXPROCESSES}); # they set a max
if (($params{NT}) || ($section->{ARCH} eq "NT4.0")) {
$end = 1; # # NT is currently limited to 1 process
$start = 1;
$p = 1;
}
# step through some process counts
# it should first reduce errors due to MAXTHREADS,
# the it will reduce errors due to integer math.
# not optimal, just good enough
my $misses = 0;
for (my $n = $start; $n <= $end; $n++) { # try some process counts
my $tryt = int ($todo / $n);
if (($sec->{MAXTHREADS}) && ($tryt > $sec->{MAXTHREADS})) {
$tryt = $sec->{MAXTHREADS};
}
# see if this is a better match than the last one
if (abs ($todo - ($n * $tryt)) < abs ($todo - ($p * $t))) {
$p = $n;
$t = $tryt;
$misses = 0;
} else {
$misses++;
last if ($misses > 1); # getting worse
}
}
$sec->{PROCESSES} = $p;
$sec->{THREADS} = $t;
return $p * $t;
}
# Allocate CLIENTCOUNT to the client machines
# try NOT to turn this into a massive linear programming project
# works best to put bigger machines last
if ($params{CLIENTCOUNT}) {
my $todo = $params{CLIENTCOUNT};
my $softcli = 0; # how many can we play with
foreach $section (@workload) { # see which are already fixed
next unless ($section->{sectionTitle} =~ /CLIENT/o);
unless (($section->{PROCESSES}) && ($section->{THREADS})) {
$softcli++;
next;
}
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my @hlist = split /[\s,]/, $slist;
my $hcnt = (1 + $#hlist);
# subtract fixed entries
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 1;
$todo -= $tcount * $section->{PROCESSES} * $hcnt;
$clientProcCount += $section->{PROCESSES} * $hcnt; # total processes
$params{DEBUG} &&
print "Fixed load group with $hcnt hosts: $section->{PROCESSES} x $tcount\n";
}
$params{DEBUG} &&
print "Allocating $todo clients over $softcli groups\n";
if ($softcli) {
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
next if (($section->{PROCESSES}) && ($section->{THREADS}));
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my @hlist = split /[\s,]/, $slist;
my $hcnt = (1 + $#hlist);
#print "todo=$todo softcli=$softcli hcnt=$hcnt\n";
$todo -= $hcnt * figurePT ($section, $todo / ($softcli * $hcnt));
$clientProcCount += $hcnt * $section->{PROCESSES}; # total procs
$softcli--;
last if ($softcli <= 0); # should not happen
}
}
if ($todo) {
print "Warning: Could not allocate $todo of $params{CLIENTCOUNT} clients.\n";
$params{CLIENTCOUNT} -= $todo;
}
} else { # figure out the client count
my $cnt = 0;
foreach $section (@workload) { # see which are already fixed
next unless ($section->{sectionTitle} =~ /CLIENT/o);
next unless ($section->{PROCESSES});
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my @hlist = split /[\s,]/, $slist;
my $hcnt = (1 + $#hlist);
# 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);
}
# This has to be written into save workload file for later processing
unless ($params{FREQUENCY}) { # unless frequency set on command line
my $chartp = ($params{CHARTPOINTS}) ? $params{CHARTPOINTS} : 464;
# approximate data points for good graphs (up to 2 times this)
$params{FREQUENCY} = int ($testsecs / $chartp);
if ($params{FREQUENCY} < 2) { # fastest is every 2 seconds
$params{FREQUENCY} = 2;
} elsif ($params{FREQUENCY} > 60) { # slowest is every minute
$params{FREQUENCY} = 60;
}
}
{ # set a unique block id on every section
my $id = 0;
my $configSeen = 0;
my $defaultSeen = 0;
foreach $section (@workload) {
if ($section->{"sectionTitle"} =~ /^CONFIG$/) {
next if $configSeen;
$configSeen++;
}
if ($section->{"sectionTitle"} =~ /^DEFAULT$/) {
next if $defaultSeen;
$defaultSeen++;
}
$id++; # number 1, 2, ...
if ($section->{"sectionTitle"} =~ /^(CONFIG|CLIENT)$/) {
$section->{BLOCKID} = $id;
} else {
push @{$section->{"lineList"}}, "blockID\t$id\n";
}
}
}
# Write the version we pass to mailclient
writeWorkloadFile ("$resultdir/work.wld", \@workload,
\@scriptWorkloadSections);
# Write the complete inclusive version
writeWorkloadFile ("$resultdir/all.wld", \@workload);
setConfigDefaults(); # pick up any missing defaults
unless ($#protocolsAll > 0) {
die "No protocols found. Test Failed!\n";
}
print "Starting: ", scalar(localtime), "\n";
# redirect STDERR
open SAVEERR, ">&STDERR";
open(STDERR, ">$resultdir/stderr") || warn "Can't redirect STDERR:$!\n";
$totalProcs = 0; # number of clients started
# iterate over every client in the testbed, complete the cmd and rsh
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/o);
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 1;
# Build the initial Mailclient command line
my $preCmd = ($section->{COMMAND})
? $section->{COMMAND} : $params{CLIENTCOMMAND};
$preCmd .= " -s -t $params{TIME} -f $params{FREQUENCY}";
$preCmd .= " -d" if ($params{DEBUG});
$preCmd .= " -r" if ($params{TELEMETRY});
$preCmd .= " -R $params{RAMPTIME}" if ($params{RAMPTIME});
$preCmd .= " -m $params{MAXERRORS}" if ($params{MAXERRORS});
$preCmd .= " -M $params{MAXBLOCKS}" if ($params{MAXBLOCKS});
$preCmd .= " -n 1 -N $tcount";
$preCmd .= ($params{USEGROUPS} && $section->{GROUP})
? " -H $section->{GROUP}" : " -H $cli";
my $stdout = "$tmpdir/localhost.out";
$totalProcs += $tcount;
do 'makeindex.pl' || warn "$@\n"; # html index
printf "\nTest duration: %d %s. Rampup time: %d %s. Number of clients: %d\n",
figureTimeNumber ($params{TIME}),
figureTimeUnits ($params{TIME}, "seconds"),
figureTimeNumber ($params{RAMPTIME}),
figureTimeUnits ($params{RAMPTIME}, "seconds"),
$totalProcs;
print STDERR "localhost: cd $params{TEMPDIR}; $preCmd\n";
# Redirect STDIN, and STDOUT
#open SAVEIN, "<STDIN";
open STDIN, "<$resultdir/work.wld"
|| die "Coundn't open $resultdir/work.wld for input\n";
open SAVEOUT, ">&STDOUT";
open STDOUT, ">$stdout"
|| die "Couldnt open $stdout for output\n";
chdir $params{TEMPDIR} || die "Could not cd $params{TEMPDIR}: $!\n";
system $preCmd;
close STDOUT;
open STDOUT, ">&SAVEOUT";
printf "Test done.\n";
chdir $cwd || die "Could not cd $cwd: $!\n";
last; # only do the first one
}
} else { # not NT (forking works)
foreach $section (@workload) { # do pre run commands
next unless ($section->{sectionTitle} =~ /PRETEST/o);
unless ($section->{COMMAND}) {
print "PreTest with no Command for $section->{sectionParams}\n";
next;
}
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $myCmd = $section->{COMMAND};
$myCmd =~ s/%f/$params{FREQUENCY}/; # fill in frequency variable
if ($myCmd =~ m/%c/o) { # dont force down if count is used
$count = $testsecs / $params{FREQUENCY};
$myCmd =~ s/%c/$count/; # fill in count variable
}
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
foreach $cli (split /[\s,]/, $slist) {
print "Running pre test command on $cli\n";
open PRE, ">>$resultdir/$cli-pre.log";
print PRE "========\n";
print PRE "$myCmd\n";
print PRE "========\n";
close PRE;
print STDERR "$cli: $myCmd\n"; # log the actual command
forkproc ($rsh, $cli, $myCmd,
"/dev/null", "$resultdir/$cli-pre.log");
}
foreach $cli (split /[\s,]/, $slist) {
wait(); # run multiple PRETEST section sequentially
}
}
foreach $section (@workload) { # start monitors
next unless ($section->{sectionTitle} =~ /MONITOR/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $myCmd = ($section->{COMMAND})
? $section->{COMMAND} : $params{MONITORCOMMAND};
my $forceDown = 0;
$myCmd =~ s/,/ /g; # turn commas into spaces BACK COMPATIBIILITY
$myCmd =~ s/%f/$params{FREQUENCY}/; # fill in frequency variable
if ($myCmd =~ m/%c/o) { # dont force down if count is used
$count = $testsecs / $params{FREQUENCY};
$myCmd =~ s/%c/$count/; # fill in count variable
} else {
$forceDown = 1;
}
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
foreach $cli (split /[\s,]/, $slist) {
printf "Monitoring on $cli\n";
open PRE, ">>$resultdir/$cli-run.log";
print PRE "========\n";
print PRE "$myCmd\n";
print PRE "========\n";
close PRE;
print STDERR "$cli: $myCmd\n"; # log the actual command
$pid = forkproc ($rsh, $cli, $myCmd,
"/dev/null", "$resultdir/$cli-run.log");
push @forceDownPids, $pid if ($forceDown); # save PID for shutdown
}
}
print "Starting clients (errors logged to $resultdir/stderr)\n";
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
next unless ($section->{PROCESSES}); # unused client
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
my $pcount = $section->{PROCESSES};
my $tcount = ($section->{THREADS}) ? $section->{THREADS} : 0;
my $tempdir;
if ($section->{TEMPDIR}) {
$tempdir = $section->{TEMPDIR};
} elsif ($params{TEMPDIR}) {
$tempdir = $params{TEMPDIR};
}
my $preCmd = "./" . (($section->{COMMAND})
? $section->{COMMAND} : $params{CLIENTCOMMAND});
$preCmd .= " -s -t $params{TIME} -f $params{FREQUENCY}";
$preCmd .= " -d" if ($params{DEBUG});
$preCmd .= " -r" if ($params{TELEMETRY});
$preCmd .= " -R $params{RAMPTIME}" if ($params{RAMPTIME});
if ($params{MAXERRORS}) {
# distribute error count over processes, rounding up
my $n = int (($params{MAXERRORS} + $clientProcCount - 1)
/ $clientProcCount);
$n = 1 if ($n < 1);
$preCmd .= " -m $n";
}
if ($params{MAXBLOCKS}) {
# distribute block count over processes, rounding up
my $n = int (($params{MAXBLOCKS} + $clientProcCount - 1)
/ $clientProcCount);
$n = 1 if ($n < 1);
$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");
foreach $cli (split /[\s,]/, $slist) {
my $stdout = getClientFilename ($cli, $section);
my $myCmd = $preCmd;
$myCmd .= ($params{USEGROUPS} && $section->{GROUP})
? " -H $section->{GROUP}" : " -H $cli";
if ($tcount) {
$myCmd .= " -N $tcount";
printf "Starting %d x %d on $cli\n", $pcount, $tcount;
$totalProcs += $pcount * $tcount;
} else {
printf "Starting %d processes on $cli\n", $pcount;
$totalProcs += $pcount;
}
print STDERR "$cli: $myCmd\n"; # log the actual command
$pid = forkproc ($rsh, $cli, $myCmd,
"$resultdir/work.wld", $stdout);
push @localPids, $pid if ($cli =~ /^localhost$/i);
}
}
if (@localPids) {
# print "Trapping extraneous local signals\n";
# This doesnt trap quite right. We dont die, but shell returns...
$SIG{ALRM} = 'IGNORE'; # in case we get an ALRM from the mailclient
}
printf "\nTest duration: %d %s. Rampup time: %d %s. Number of clients: %d\n",
figureTimeNumber ($params{TIME}),
figureTimeUnits ($params{TIME}, "seconds"),
figureTimeNumber ($params{RAMPTIME}),
figureTimeUnits ($params{RAMPTIME}, "seconds"),
$totalProcs;
do 'makeindex.pl' || warn "$@\n"; # html index
print "Waiting for test to finish.\n";
print "Waiting: ", scalar(localtime), "\n";
# wait for children to finish
$pid = wait();
if (@forceDownPids) { # shut down after the first return.
print "Shutting down @forceDownPids\n";
kill 1 => @forceDownPids; # sigHUP
# kill 9 => @forceDownPids; # sigTERM
}
while ($pid != -1) { # wait for all children
$pid = wait();
}
foreach $section (@workload) { # do post test commands
next unless ($section->{sectionTitle} =~ /POSTTEST/o);
unless ($section->{COMMAND}) {
print "PostTest with no command for $section->{sectionParams}\n";
next;
}
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $myCmd = $section->{COMMAND};
$myCmd =~ s/%f/$params{FREQUENCY}/; # fill in frequency variable
if ($myCmd =~ m/%c/o) { # dont force down if count is used
$count = $testsecs / $params{FREQUENCY};
$myCmd =~ s/%c/$count/; # fill in count variable
}
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
foreach $cli (split /[\s,]/, $slist) {
printf "Running post test command on $cli\n";
open PRE, ">>$resultdir/$cli-post.log";
print PRE "========\n";
print PRE "$myCmd\n";
print PRE "========\n";
close PRE;
print STDERR "$cli: $myCmd\n"; # log the actual command
forkproc ($rsh, $cli, $myCmd,
"/dev/null", "$resultdir/$cli-post.log");
}
foreach $cli (split /[\s,]/, $slist) {
wait(); # run multiple POSTTEST section sequentially
}
}
}
print STDERR "\nDone.\n";
close(STDERR);
open STDERR, ">&SAVEERR";
print "\nClients done: ", scalar(localtime), "\n";
print "Collecting results\n";
do 'reduce.pl' || die "$@\n"; # generate graphs and sums
print "Generating results pages\n";
do 'report.pl' || die "$@\n";
# Now display that data to console
if ($params{VERBOSE}) {
fileShow ($resultstxt);
print "\n";
}
print "Processing done: ", scalar (localtime), "\n";
pathprint ("\nResults (text):\t$resultstxt\n");
pathprint ( "Results (HTML):\t$resultshtml\n");
print "Index of runs: \tfile://$cwd/$resultbase/index.html\n";
# Now check for major problems in the stderr file
if (open(RESULTSTXT, "$resultdir/stderr")) {
$ERRCNT=0;
while (<RESULTSTXT>) { $ERRCNT++; }
close(RESULTSTXT);
pathprint ("Error log ($ERRCNT lines):\t$resultdir/stderr\n");
}
{ # list user requested logging
my @logfiles = <$resultdir/*-pre.log>;
if (@logfiles) {
foreach $f (@logfiles) {
print "Pre test log: \t$f\n";
}
}
@logfiles = <$resultdir/*-run.log>;
if (@logfiles) {
foreach $f (@logfiles) {
print "Monitoring log: \t$f\n";
}
}
@logfiles = <$resultdir/*-post.log>;
if (@logfiles) {
foreach $f (@logfiles) {
print "Post test log: \t$f\n";
}
}
}
print "Mailmaster done: ", scalar(localtime), "\n"; exit 0;

114
mstone/bin/makeindex.pl Executable file
Просмотреть файл

@ -0,0 +1,114 @@
#!/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
# 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): 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.
#####################################################
# usage: perl -Ibin makeindex.pl
# Look at all the results files and create a top level index
unless ($resultbase) { # pick up systematic defaults, if needed
do 'args.pl'|| die $@;
parseArgs(); # parse command line
}
($testname = $params{WORKLOAD}) =~ s:conf/::;
$testname =~ s:.wld::;
my $entry = "";
$entry .= "<TR><TD><BR><A HREF=\"$params{TSTAMP}/results.html\">$params{TSTAMP}</A></TD>";
$entry .= "<TD>$testname</TD>\n";
$entry .= "<TD>$params{TITLE}</TD>\n";
$entry .= "<TD>$params{TIME}</TD>\n";
$entry .= "<TD>$params{CLIENTCOUNT}</TD>\n";
$entry .= "<TD><A HREF=\"$params{TSTAMP}/all.wld\">workload</A></TD>\n";
$entry .= "<TD><A HREF=\"$params{TSTAMP}/stderr\">stderr</A></TD></TR>\n";
if (-r "$resultbase/index.html") {
fileInsertAfter ("$resultbase/index.html",
"^<!-- INSERT TAGS HERE",
$entry);
} else { # create index from scratch
open(INDEXNEW, ">$resultbase/index.new") ||
die "Couldn't open $resultbase/index.new: $!";
print INDEXNEW <<END;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<TITLE>
MailStone Results
</TITLE>
<HEAD>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#FF0000" ALINK="#000088">
<A HREF=$mailstoneURL>Mailstone documentation</A><BR>
<TABLE BORDER=2>
<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>
</TR>
<!-- INSERT TAGS HERE - DO NOT DELETE THIS LINE -->
END
print INDEXNEW $entry; # put in this entry
# Add in any existing entries
# get a list of all the results files
@resall = <$resultbase/*/results.html>;
# Write out all the links
# This could be rather slow, but we only do it when index.html is missing
foreach $filefull (reverse @resall) {
my $file = $filefull;
$file =~ s:$resultbase/::;
if ($file eq $params{TSTAMP}) { next; } # written above
my $dir = $file;
$dir =~ s:/results.html::;
# dont read in old workloads, it will override the current one
print INDEXNEW "<TR><TD><BR><A HREF=\"$file\">$dir</A></TD>\n";
print INDEXNEW "<TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>\n";
print INDEXNEW "<TD><A HREF=\"$dir/all.wld\">workload</A></TD>\n";
print INDEXNEW "<TD><A HREF=\"$dir/stderr\">stderr</A></TD></TR>\n";
}
print INDEXNEW <<END;
</TABLE>
</BODY>
</HTML>
END
close (INDEXNEW);
fileBackup ("$resultbase/index.html");
rename ("$resultbase/index.new", "$resultbase/index.html");
print "Created $resultbase/index.html\n";
}
return 1;

414
mstone/bin/makeusers.pl Executable file
Просмотреть файл

@ -0,0 +1,414 @@
#!/usr/local/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
# 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): 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.
#####################################################
# script to create test user accounts for Netscape Messaging Server 3, 4
#
# Given a set of parameters, this script will create an LDIF file
# for a number of email users of the form:
# test1, test2, test3, ...
#
# usage: perl create_accounts_ldif [users] [broadcast] [postmaster] [ options ]
# [ -a allUsersAlias ]
# [ -b basedn ]
# [ -d maildomain ]
# [ -f firstaccount ]
# [ -k ]
# [ -m mailhost ]
# [ -n numaccounts ]
# [ -o outputfile ]
# [ -p password ]
# [ -s storebase ]
# [ -u username ]
# [ -v ]
# [ -w workload ]
# [ -x maxstores ]
# [ -3 ]
#
# perl/bin/perl -Ibin -- bin/makeusers.pl -d mailhost.example.com -m mailhost.example.com -b 'o=example.com' -u mailhost-test -n 100 -4 -o mailhost100.ldif
# Create the ldif for the user accounts and/or broadcast, postmaster account.
#
# The ldif then must be added to
# the directory by hand (ldapadd, or through the dir admin server's
# Database Mgmt->Add entries from an ldif file).
# A faster way
# is to export the existing directory, append the results of
# this script, and re-import the combined file. This can be
# done using the following Netscape Directory Server commands:
# stop-slapd
# db2ldif outputfile
# [ merge files ]
# ldif2db inputfile # for DS4 you would typically use -noconfig
# start-sladp
#
print "Netscape Mailstone.\nCopyright (c) 1998,1999 Netscape Communications Corp.\n";
# server to be used in the internet mail address of the users
$domain = "newdomain.example.net";
# machine that will act as the user's mailhost
$mailhost = "mailhost.example.net";
# base dn for the user entries, e.g. o=Ace Industry,c=US
$basedn = "o=Benchmark Lab, c=US";
# name of broadcast account
$bcastacct = "allusers";
# name of broadcast account
$postmasteraddr = "root\@localhost";
# base name to build user names, will construct test0, test1, ...
$username = "test%ld";
# user passwds, in SHA format, the passwd below is 'netscape'
#$userpassword = "{SHA}aluWfd0LYY9ImsJb3h4afrI4AXk=";
# these can also be imported as cleartext
$userpassword = "netscape";
# 0: no numbered passwords, 1: number with userID
$maxpass = 0;
# first account to use
$firstaccount = 0;
# number of user accounts to create ($first - $first+$num-1)
$numaccounts = 1_000;
# For larger systems, spreading the users over multiple partitions
# is usually a good idea. This example assumes you have
# created partitions named p0, p1, etc.
# store partition base name
$storebase = "p%ld";
# max store number (0 - maxstores-1), skip if 0
$maxstores = 0;
#default to msg 4 schemas
$usemsg4schema = 1;
#default to writing to stdout
$outfile = STDOUT;
# Initial UID for genpasswd
$firstuid = 1000;
sub usage {
print "Usage: perl -Ibin -- makeusers [users] [broadcast] [postmaster]\n";
print "\t[ -w workload ] [ -o outputFile ]\n";
print "\t[ -d mailDomain ] [ -m mailHost ] [ -b baseDN ]\n";
print "\t[ -u username ] [ -f firstAccount ] [ -n numAccounts ]\n";
print "\t[ -p password ] [ -k ]\n";
print "\t[ -s storeBase ] [ -x numStores ]\n";
print "\t[ -a allUsersAlias ] [ -t postmasterAddress ]\n";
print "\t[ -3 ]|[ -4 ]\n";
}
sub readWorkConfig { # read the workload in, parse our params
my $workloadfile = shift || die "Workload file name expected\n";
do 'args.pl'|| die $@;
readWorkloadFile ($workloadfile, \@workload)
|| die "Error reading workload: $@\n";
# assign all the parameters from the config
$mailhost = $defaultSection->{SERVER}
if ($defaultSection->{SERVER});
if ($defaultSection->{ADDRESSFORMAT}) {
my $addr = $defaultSection->{ADDRESSFORMAT};
$addr =~ s/^.*@//;
$domain = $addr;
}
if ($defaultSection->{LOGINFORMAT}) {
my $user = $defaultSection->{LOGINFORMAT};
#$user =~ s/%ld$//;
$username = $user;
}
$numaccounts = $defaultSection->{NUMLOGINS}
if ($defaultSection->{NUMLOGINS});
$firstaccount = $defaultSection->{FIRSTLOGINS}
if ($defaultSection->{FIRSTLOGINS});
$userpassword = $defaultSection->{PASSWDFORMAT}
if ($defaultSection->{SERVER});
if ($userpassword =~ m/%ld/) { # see if numbered passwords
$maxpass++;
#$userpassword =~ s/%ld//g;
}
# what isnt set: basedn, storebase, maxstores, usemsg4schema
}
while (@ARGV) {
$arg = shift(@ARGV);
if ($arg =~ /^-a$/i) { # allusers (broadcast) user name
$bcastacct = shift(@ARGV);
next;
}
if ($arg =~ /^-b$/i) { # LDAP base DN
$basedn = shift(@ARGV);
next;
}
if ($arg =~ /^-d$/i) { # mail domain
$domain = shift(@ARGV);
next;
}
if ($arg =~ /^-f$/i) { # initial account
$firstaccount = shift(@ARGV);
next;
}
if ($arg =~ /^-k$/i) { # use numbered passwords
$maxpass++;
next;
}
if ($arg =~ /^-h$/i) { # help
usage();
exit 0;
}
if ($arg =~ /^-m$/i) { # mail server name
$mailhost = shift(@ARGV);
next;
}
if ($arg =~ /^-n$/i) { # number of accounts
$numaccounts = shift(@ARGV);
next;
}
if ($arg =~ /^-o$/i) { # name output file
my $fname = shift || die "File name expected\n";
open OUTFILE, ">$fname" || die "Error opening file $@\n";
$outfile = OUTFILE;
next; # use msg4 user admin schema
}
if ($arg =~ /^-p$/i) { # password
$userpassword = shift(@ARGV);
next;
}
if ($arg =~ /^-s$/i) { # base name for above
$storebase = shift(@ARGV);
next;
}
if ($arg =~ /^-t$/i) { # postmaster address
$postmasteraddress = shift(@ARGV);
next;
}
if ($arg =~ /^-u$/i) { # user name base
$username = shift(@ARGV);
next;
}
if ($arg =~ /^-v$/i) { # be verbose
$verbose++;
next;
}
# do this when read, so that later switches can override
if ($arg =~ /^-w$/i) { # get a workload file
readWorkConfig (shift(@ARGV));
next;
}
if ($arg =~ /^-x$/i) { # number of partitions (0 to skip)
$maxstores = shift(@ARGV);
next;
}
if ($arg =~ /^-3$/) { # no msg4 schema
$usemsg4schema = 0;
next;
}
if ($arg =~ /^-4$/) { # use msg4 user admin schema
$usemsg4schema = 1;
next;
}
if ($arg =~ /^users$/i) {
$genusers++;
next;
}
if ($arg =~ /^broadcast$/i) {
$genbroadcast++;
next;
}
if ($arg =~ /^passwd$/i) {
$genpasswd++;
next;
}
if ($arg =~ /^postmaster$/i) {
$genpostmaster++;
next;
}
print STDERR "Unknown argument $arg. Use -h for help.\n";
exit 1;
}
unless (($genusers) || ($genbroadcast) || ($genpasswd) || ($genpostmaster)) {
print STDERR "Must specify mode [users] [broadcast] [postmaster] ...\n";
usage();
exit 0;
}
# specify number fields, if needed
unless ($username =~ /%ld/) {
$username .= '%ld';
}
if (($maxpass) && !($userpassword =~ /%ld/)) {
$userpassword .= '%ld';
}
if (($maxstores) && !($storename =~ /%ld/)) {
$storename .= '%ld';
}
if ($verbose) {
print STDERR "Here is the configuration:\n";
print STDERR "baseDN='$basedn' \t";
print STDERR (($usemsg4schema) ? "-4\n" : "-3\n");
print STDERR "mailHost='$mailhost' \tdomain='$domain'\n";
print STDERR "userName='$username' \tnumAccounts=$numaccounts \tfirstAccount=$firstaccount\n";
print STDERR "userPassword='$userpassword'\n";
print STDERR "allUsersAccount='$bcastacct'\n" if ($genbroadcast);
print STDERR "postmasterAddress='$postmasterAddress'\n" if ($genpostmaster);
}
if ($genusers) { # Create the user accounts
$storenum=0;
for ($i = $firstaccount; $i < $firstaccount+$numaccounts; $i++) {
# build user account name
my $acctname = $username;
$acctname =~ s/%ld/$i/; # insert user number
my $password = $userpassword;
$password =~ s/%ld/$i/; # insert user number
# MAKE SURE THERE ARE NO TRAILING SPACES IN THE LDIF
my $extradata = "";
if ($maxstores > 0) { # assign them to a store
my $storename = $storebase;
$storename =~ s/%ld/$storenum/;
$extradata .= "mailmessagestore: $storename\n";
$storenum++;
$storenum=0 if ($storenum >= $maxstores);
}
$extradata .= "objectclass: nsMessagingServerUser\n"
if ($usemsg4schema);
print $outfile <<END;
dn: uid=$acctname, $basedn
userpassword: $password
givenname: $acctname
sn: $acctname
cn: $acctname
uid: $acctname
mail: $acctname\@$domain
mailhost: $mailhost
maildeliveryoption: mailbox
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: mailRecipient
$extradata
END
}
}
if ($genbroadcast) { # Create the broadcast account
# MAKE SURE THERE ARE NO TRAILING SPACES IN THE LDIF
my $password = $userpassword;
$password =~ s/%ld//; # strip user number
# initial part
print $outfile <<END;
dn: uid=$bcastacct, $basedn
userpassword: $password
givenname: $bcastacct
sn: $bcastacct
cn: $bcastacct
uid: $bcastacct
mail: $bcastacct\@$domain
mailhost: $mailhost
maildeliveryoption: forward
END
# now put in each address
for ($i = $firstaccount; $i < $firstaccount+$numaccounts; $i++) {
# build user account name
my $acctname = $username;
$acctname =~ s/%ld/$i/; # insert user number
print $outfile "mailforwardingaddress: $acctname\@$domain\n";
}
# final part
print $outfile <<END;
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: mailRecipient
END
}
if ($genpostmaster) { # Create the postmaster account
# MAKE SURE THERE ARE NO TRAILING SPACES IN THE LDIF
print $outfile <<END;
dn: cn=postmaster, $basedn
cn: postmaster
mail: postmaster\@$domain
mailalternateaddress: postmaster\@$mailhost
mgrprfc822mailmember: $postmasterAddress
objectclass: top
objectclass: mailGroup
objectclass: groupOfUniqueNames
END
}
# mixing passwd output with the ldif output above would be quite silly
if ($genpasswd) { # Create passwd entries for makeusers
for ($i = $firstaccount; $i < $firstaccount+$numaccounts; $i++) {
# build user account name
my $acctname = $username;
$acctname =~ s/%ld/$i/; # insert user number
my $password = $userpassword;
$password =~ s/%ld/$i/; # insert user number
my $uid = $firstuid + $i;
print $outfile "$acctname:$password:$uid:$uid:Mail user $acctname:/home/$acctname:/bin/sh\n";
}
}
exit 0;

0
mstone/bin/process.pl Normal file
Просмотреть файл

157
mstone/bin/protoconf.pl Normal file
Просмотреть файл

@ -0,0 +1,157 @@
# 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): 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.
#####################################################
# This define the structures that hold summary, client, and graph data,
# This sets the names used for display. Can be internationalized.
# All top level names are here (both timers and scalars).
# Any unlisted names will map to themselves.
%timerNames
= (
#internal name, Printed name
"total", "total",
"conn", "connect",
"banner", "banner",
"login", "login",
"cmd", "command",
"submit", "submit",
"retrieve", "retrieve",
"logout", "logout",
"idle", "idle",
"connections", "connections",
"blocks", "blocks",
);
# This sets the names used for display. Can be internationalized.
%fieldNames
= (
#internal name, Printed name
"Try", "Try",
"Error", "Error",
"BytesR", "BytesR",
"BytesW", "BytesW",
"Time", "Time",
"TimeMin", "TMin",
"TimeMax", "TMax",
"Time2", "TStd",
);
# hold time graphs for each protocol
%graphs = ();
# Totals are done during plotting, if needed
%finals = (); # create base finals hash
# These are sections that dont get passed to mailclient (case insensitive)
@scriptWorkloadSections
= (
"Config", # special, references %params
"Client", # testbed client(s)
"Graph", # graph generation
"Setup", # things to run with ./setup
"Startup", # things to run before test
"Monitor", # other performance monitoring
"PreTest", # things to run before test
"PostTest", # things to run after test
);
# These are sections that arent protocols. Anything else must be.
@nonProtocolSections
= (@scriptWorkloadSections, ("Default"));
# These are the known workload parameters (as they will print)
# These are coerced to upper case internally (do NOT internationize)
@workloadParameters
= (
"addressFormat",
"arch",
"blockID",
"blockTime",
"chartHeight",
"chartPoints",
"chartWidth",
"clientCount",
"command",
"comments",
"file",
"firstAddress",
"firstLogin",
"frequency",
"gnuplot",
"group",
"idleTime",
"leaveMailOnServer",
"loginFormat",
"loopDelay",
"numAddresses",
"numLogins",
"numLoops",
"numRecips",
"mailClient",
"maxBlocks",
"maxClients",
"maxErrors",
"maxThreads",
"maxProcesses",
"passwdFormat",
"processes",
"rampTime",
"rcp",
"rsh",
"sequentialAddresses",
"sequentialLogins",
"server",
"smtpMailFrom",
"sysConfig",
"threads",
"telemetry",
"tempDir",
"time",
"title",
"TStamp",
"useAuthLogin",
"useEHLO",
"weight",
"wmapBannerCmds",
"wmapClientHeader",
"wmapInBoxCmds",
"wmapLoginCmd",
"wmapLoginData",
"wmapLogoutCmds",
"wmapMsgReadCmds",
"wmapMsgWriteCmds",
"workload",
);
return 1;

1057
mstone/bin/reduce.pl Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

605
mstone/bin/report.pl Normal file
Просмотреть файл

@ -0,0 +1,605 @@
# 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): 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.
#####################################################
# This file deals with the summary data only
# Should be packages
do 'genplot.pl' || die "$@\n";
sub walkSetupTotals {
my $a = shift; my $f = shift; my $p = shift;
if ($p =~ /(\w+):(\w+):$/) {
my $tm = $2;
if (!($finals{Total}->{$tm}->{$f})) {
$finals{Total}->{$tm}->{$f} = $a;
} elsif ($f =~ /Min$/) {
$finals{Total}->{$tm}->{$f} = $a
if (($a > 0.0) && ($a < $finals{Total}->{$tm}->{$f}));
} elsif ($f =~ /Max$/) {
$finals{Total}->{$tm}->{$f} = $a if ($a > $finals{Total}->{$tm}->{$f});
} else {
$finals{Total}->{$tm}->{$f} += $a;}
}
elsif ($p =~ /(\w+):$/) {
$finals{Total}->{$f} += $a;
}
}
sub setupTotals {
# Figure out combined timers for "Total" protocol
# We might do a smarter merge here (look at context and try to match order)
# As long as the first protocol is a superset, it wont matter
my @tnames;
foreach $proto (@protocols) {
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n;
$t =~ s/([][{}*+?^.\/])/\\$1/g; # quote regex syntax
my $found = 0;
foreach $tn (@tnames) { # see if it is in the list already
next unless ($tn =~ /$t/);
$found = 1;
last;
}
#print "proto $proto: Found $n\n" if ($found > 0);
next if ($found > 0);
#print "proto $proto: Add $n\n";
push @tnames, $n; # add to list
}
}
#print "'Total' timers @tnames\n";
$protocolFields{"Total"} = \@tnames;
# Create "Total" hashes
$finals{Total} = ArrayInstance->new();
foreach $n (@{$protocolFields{"Total"}}) { # all timers
my $t = $n; # dont modify original list
if ($t =~ /^\[(\w+)\]$/) { # Timer case, strip off brackets
$finals{Total}->{$1} = ArrayInstance->new();
#print "Creating Total timer field $1\n";
} else { # scalar
$finals{Total}->{$n} = 0;
#print "Creating Total scalar field $n\n";
}
}
# Total finals array
foreach $proto (@protocols) {
foreach $t (@{$protocolFields{$proto}}) {
if ($t =~ /^\[(\w+)\]$/) { # Timer case, strip off brackets
my $tm = $1;
foreach $f (@timerFieldsAll) {
my $a = $finals{$proto}->{$tm}->{$f};
if (!($finals{Total}->{$tm}->{$f})) { # never touched
$finals{Total}->{$tm}->{$f} = $a;
} elsif ($f =~ /Min$/) {
$finals{Total}->{$tm}->{$f} = $a
if (($a > 0.0)
&& ($a < $finals{Total}->{$tm}->{$f}));
} elsif ($f =~ /Max$/) {
$finals{Total}->{$tm}->{$f} = $a
if ($a > $finals{Total}->{$tm}->{$f});
} else {
$finals{Total}->{$tm}->{$f} += $a;
}
}
} else {
$finals{Total}->{$t} += $finals{$proto}->{$t};
}
}
}
# Convert Time2 to standard deviation
foreach $proto (@protocolsAll) {
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
if ($t =~ /^\[(\w+)\]$/) { $t = $1; } # strip off brackets
next unless ($finals{$proto}->{$t}); # proto doesnt have timer
next unless ($finals{$proto}->{$t}->{Try});
next unless ($finals{$proto}->{$t}->{Time2} > 0);
my $ss = $finals{$proto}->{$t}->{Time2};
my $tot = $finals{$proto}->{$t}->{Time};
my $n = $finals{$proto}->{$t}->{Try};
next unless ($n > 0); # skip if this is 0
my $var = ($ss - (($tot * $tot) / $n)) / $n;
print "$proto->$t var < 0: Time2=$ss Time=$tot n=$n\n"
if ($var < 0);
$finals{$proto}->{$t}->{Time2} = ($var > 0) ? sqrt ($var) : 0.0;
}
}
# Divide total times by trys to get averate time
foreach $proto (@protocolsAll) {
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
if ($t =~ /^\[(\w+)\]$/) { $t = $1; } # strip off brackets
next unless ($finals{$proto}->{$t}); # proto doesnt have timer
($finals{$proto}->{$t}->{Try}) || next;
$finals{$proto}->{$t}->{Time} /= $finals{$proto}->{$t}->{Try}
}
}
}
# The text version is designed to be machine processable
# commify and kformat are not used
sub genTextReport {
fileBackup ($resultstxt); # if processing as we go, backup old file
# Open a text file to hold the results
open(RESULTSTXT, ">$resultstxt") ||
die "Couldn't open $resultstxt: $!";
# Store results as text
printf RESULTSTXT "---- Netscape MailStone Results $params{TSTAMP} ----\n";
printf RESULTSTXT "\t\t%s\n", $params{TITLE};
printf RESULTSTXT "\t\t%s\n", $params{COMMENTS};
printf RESULTSTXT "\n";
printf RESULTSTXT "Test duration: %d %s. Rampup: %d %s. Reported duration %s seconds\n",
figureTimeNumber ($params{TIME}),
figureTimeUnits ($params{TIME}, "minutes"),
figureTimeNumber ($params{RAMPTIME}),
figureTimeUnits ($params{RAMPTIME}, "seconds"), $realTestSecs;
printf RESULTSTXT "Number of reporting clients: %s of %s\n",
$reportingClients, $totalProcs;
foreach $proto (@protocolsAll) {
# do op counters
printf RESULTSTXT "\n%-15s ", $proto;
foreach $f (@timerFieldsAll) {
#($f =~ m/^Time2$/o) && next;
printf RESULTSTXT "%13s",
($fieldNames{$f}) ? $fieldNames{$f} : $f;
}
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
unless ($t =~ /^\[(\w+)\]$/) { # scalar case
#next; # skip scalars for now
# do scalar counters. Column should line up with "Try"
printf RESULTSTXT "\n%-15s ",
$proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t);
printf RESULTSTXT
"%13s", $finals{$proto}->{$t};
next;
} else { # strip off brackets
$t = $1;
}
printf RESULTSTXT "\n%-15s ",
$proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t);
foreach $f (@timerFieldsAll) {
#($f =~ m/^Time2$/o) && next;
if ($f =~ m/Time/o) {
printf RESULTSTXT
"%13.3f", $finals{$proto}->{$t}->{$f};
} elsif ($f =~ m/Bytes/o) {
printf RESULTSTXT
"%13d", $finals{$proto}->{$t}->{$f};
} else {
printf RESULTSTXT
"%13s", $finals{$proto}->{$t}->{$f};
}
}
}
# do ops/sec
printf RESULTSTXT "\n\n%-15s ", $proto;
foreach $f (@timerFieldsAll) {
($f =~ m/^Time/o) && next;
printf RESULTSTXT "%9s/sec",
($fieldNames{$f}) ? $fieldNames{$f} : $f;
}
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
unless ($t =~ /^\[(\w+)\]$/) { # scalar case
#next; # skip scalars for now
# do scalar counter/sec. Column should line up with "Try"
printf RESULTSTXT "\n%-15s ",
$proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t) . "/s";
printf RESULTSTXT
"%13.3f", $finals{$proto}->{$t} / $realTestSecs;
next;
} else {
$t = $1;
}
printf RESULTSTXT "\n%-15s ",
$proto . ":" . (($timerNames{$t}) ? $timerNames{$t} : $t) . "/s";
foreach $f (@timerFieldsAll) {
($f =~ m/^Time/o) && next;
if ($f =~ m/Bytes/o) {
printf RESULTSTXT
"%13d",
$finals{$proto}->{$t}->{$f} / $realTestSecs;
} else {
printf RESULTSTXT
"%13.3f",
$finals{$proto}->{$t}->{$f} / $realTestSecs;
}
}
}
printf RESULTSTXT "\n\n";
}
if ($params{SYSCONFIG}) {
print RESULTSTXT "\nSytem config details\n";
if (($params{SYSCONFIG} =~ m/^\S+$/o)
&& (open(SCFILE, "<$params{SYSCONFIG}"))) {
while (<SCFILE>) {
(m/^<\S+>\s*$/o) && next; # skip HTML only on them
s/<\S+>//g; # trim out obvious HTML commands
s/<!--.*-->//g; # trim out HTML comments
print RESULTSTXT $_;
}
close(SCFILE);
} else {
my $l = $params{SYSCONFIG}; # filter similar to above
$l =~ s/<\S+>//g; # trim out obvious HTML commands
$l =~ s/<!--.*-->//g; # trim out HTML comments
$l =~ s/\\\n/\n/g; # turn quoted newline to plain newline
print RESULTSTXT $l;
}
}
close(RESULTSTXT);
}
# Write the main part of the HTML page
sub genHTMLReportStart {
fileBackup ($resultshtml); # if processing as we go, backup old file
# Open an html file to hold the results
open(RESULTSHTML, ">$resultshtml") ||
die "Couldn't open $resultshtml: $!";
print RESULTSHTML <<END;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<A NAME=TitleSection>
<TITLE>
Netscape MailStone Results $params{TSTAMP}
</TITLE>
</A>
<HEAD>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#FF0000" ALINK="#000088">
<CENTER>
<HR NOSHADE WIDTH="100%">
<H1>Netscape MailStone Results $params{TSTAMP}</H1>
<H2>$params{TITLE}</H2>
<I>$params{COMMENTS}</I>
<HR WIDTH="100%">
</CENTER>
END
printf RESULTSHTML "<BR><B>Test duration:</B> %d %s. ",
figureTimeNumber ($params{TIME}),
figureTimeUnits ($params{TIME}, "minutes");
printf RESULTSHTML "<B>Rampup:</B> %d %s. ",
figureTimeNumber ($params{RAMPTIME}),
figureTimeUnits ($params{RAMPTIME}, "seconds");
printf RESULTSHTML "<B>Reported duration:</B> %s seconds\n",
commify ($realTestSecs);
printf RESULTSHTML "<BR><B>Reporting clients:</B> %s of %s\n",
commify ($reportingClients), commify ($totalProcs);
print RESULTSHTML <<END;
<BR>
Test <A HREF="all.wld">complete workload</a> description.
Filtered <A HREF="work.wld">workload</a> description.
<BR>
Plain <A HREF="results.txt">text version</a> of results.
Log of <A HREF="stderr">stderr</a> and debugging output.
<BR>
<A NAME=MonitoringSection></A>
END
{ # list user requested logging
my @logfiles = <$resultdir/*-pre.log>;
if (@logfiles) {
foreach $f (@logfiles) {
$f =~ s/$resultdir\///o; # strip directory out
$f =~ s/-pre\.log$//o; # strip extension off
print RESULTSHTML "Pre test log: <A HREF=\"$f-pre.log\">$f</a><BR>\n";
}
}
@logfiles = <$resultdir/*-run.log>;
if (@logfiles) {
foreach $f (@logfiles) {
$f =~ s/$resultdir\///o; # strip directory out
$f =~ s/-run\.log$//o; # strip extension off
print RESULTSHTML "Monitoring log: <A HREF=\"$f-run.log\">$f</a><BR>\n";
}
}
@logfiles = <$resultdir/*-post.log>;
if (@logfiles) {
foreach $f (@logfiles) {
$f =~ s/$resultdir\///o; # strip directory out
$f =~ s/-post\.log$//o; # strip extension off
print RESULTSHTML "Post test log: <A HREF=\"$f-post.log\">$f</a><BR>\n";
}
}
}
#print RESULTSHTML
#"<CENTER><H2>Results per protocol</H2></CENTER>\n";
foreach $proto (@protocolsAll) {
printf RESULTSHTML "<A NAME=%sTable></A>\n", $proto;
printf RESULTSHTML
"<TABLE BORDER=2 CELLSPACING=2 CELLPADDING=2 COLS=%d WIDTH=\"95%%\">",
2+$#{@{$protocolFields{$proto}}};
print RESULTSHTML
"<CAPTION>$proto Counters</CAPTION>\n";
# do op counters
print RESULTSHTML
"<TR><TH>$proto</TH>\n";
foreach $f (@timerFieldsAll) {
#($f =~ m/^Time2$/o) && next;
printf RESULTSHTML "<TH>%s</TH> ",
($fieldNames{$f}) ? $fieldNames{$f} : $f;
}
print RESULTSHTML
"</TR>\n";
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
unless ($t =~ /^\[(\w+)\]$/) { # scalar case
next; # skip scalars for now
# do scalar counters. Column should line up with "Try"
printf RESULTSHTML "<TR ALIGN=RIGHT><TH>%s</TH>\n",
($timerNames{$t}) ? $timerNames{$t} : $t;
printf RESULTSHTML
"<TD>%s</TD> ",
commify ($finals{$proto}->{$t});
next;
} else {
$t = $1;
}
printf RESULTSHTML "<TR ALIGN=RIGHT><TH>%s</TH>\n",
($timerNames{$t}) ? $timerNames{$t} : $t;
foreach $f (@timerFieldsAll) {
#($f =~ m/^Time2$/o) && next;
if ($f =~ m/Time/o) {
printf RESULTSHTML
"<TD>%s</TD> ",
tformat ($finals{$proto}->{$t}->{$f});
} elsif ($f =~ m/Bytes/o) {
printf RESULTSHTML
"<TD>%s</TD> ",
kformat ($finals{$proto}->{$t}->{$f});
} else {
printf RESULTSHTML
"<TD>%s</TD> ",
commify ($finals{$proto}->{$t}->{$f});
}
}
print RESULTSHTML "</TR>\n";
}
# do ops/sec
print RESULTSHTML
"<TR><TH>$proto</TH>\n";
foreach $f (@timerFieldsAll) {
($f =~ m/^Time/o) && next;
printf RESULTSHTML "<TH>%s/sec</TH> ",
($fieldNames{$f}) ? $fieldNames{$f} : $f;
}
print RESULTSHTML
"</TR>\n";
foreach $n (@{$protocolFields{$proto}}) {
my $t = $n; # dont modify original list
unless ($t =~ /^\[(\w+)\]$/) { # scalar case
next; # skip scalars for now
# do scalar counters. Column should line up with "Try"
printf RESULTSHTML "<TR ALIGN=RIGHT><TH>%s</TH>\n",
($timerNames{$t}) ? $timerNames{$t} : $t;
printf RESULTSHTML
"<TD>%.3f</TD> ",
$finals{$proto}->{$t} / $realTestSecs;
next;
} else {
$t = $1;
}
printf RESULTSHTML "<TR ALIGN=RIGHT><TH>%s</TH>\n",
($timerNames{$t}) ? $timerNames{$t} : $t;
foreach $f (@timerFieldsAll) {
($f =~ m/^Time/o) && next;
if ($f =~ m/Bytes/o) {
printf RESULTSHTML
"<TD>%s</TD> ",
kformat ($finals{$proto}->{$t}->{$f} / $realTestSecs);
} else {
printf RESULTSHTML
"<TD>%.3f</TD> ",
$finals{$proto}->{$t}->{$f} / $realTestSecs;
}
}
print RESULTSHTML "</TR>\n";
}
printf RESULTSHTML "</TABLE> <BR>\n\n";
}
print RESULTSHTML <<END;
<BR>
<CENTER>
<A NAME=GraphSection></A>
END
}
%genplotGraphs = ();
# Call genplot; and, if a graph is generated, insert the HTML reference to it
sub genHTMLReportGraph {
my $name = shift;
my $title = shift;
my $label = shift;
my $protos = shift || die "genHTMLReportGraph: '$name' missing protocols";
my $field = shift;
my $vars = shift || die "genHTMLReportGraph: '$name' missing vars";
if ($genplotGraphs{$name}) {
print "Graph $name has already been generated.\n";
return;
}
$genplotGraphs{$name} = $title;
# Delineate and tag each graph
print RESULTSHTML "<A NAME=$name><HR SIZE=4 WIDTH=\"90%\"></A>\n";
if (genPlot ($name, $title, $label, $protos, $field, $vars) > 0) {
print RESULTSHTML <<END;
<P><H3>$title</H3>
<IMG SRC=$name.gif ALT="$label"></P>
END
} else {
print RESULTSHTML "<BR>Graph \"$name\" contained no data (@{$vars}).<BR>\n";
}
}
# Write the final parts of the HTML page
sub genHTMLReportEnd {
print RESULTSHTML <<END;
<!-- INSERT IMAGES HERE - DO NOT DELETE THIS LINE -->
</CENTER>
<A NAME=EndSection></A>
END
if ($params{SYSCONFIG}) {
print RESULTSHTML "<HR WIDTH=\"100%\">";
print RESULTSHTML "<CENTER><H2>Details</H2></CENTER>\n";
if (($params{SYSCONFIG} =~ m/^\S+$/o)
&& (open(SCFILE, "<$params{SYSCONFIG}"))) { # see if its a file
while (<SCFILE>) {
print RESULTSHTML $_;
}
close(SCFILE);
} else { # output text directly
my $l = $params{SYSCONFIG};
$l =~ s/\\\n/\n/g; # turn quoted newline to plain newline
print RESULTSHTML $l;
}
}
print RESULTSHTML <<END;
<HR NOSHADE WIDTH="100%">
</BODY>
</HTML>
END
close(RESULTSHTML);
}
# Actually generate the standard stuff
setupTotals();
genTextReport();
genHTMLReportStart();
my $graphCount = 0;
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /GRAPH/o);
my $name = $section->{sectionParams};
$name =~ s/name=\s*//; # strip off initial bit
my @varlist = split (/[\s,]+/, $section->{VARIABLES});
$graphCount++;
genHTMLReportGraph ($name, $section->{TITLE}, $section->{LABEL},
($section->{FIELD} =~ /Time/o)
? \@protocols : \@protocolsAll,
$section->{FIELD}, \@varlist);
}
if ($graphCount <= 0) { # use built ins
# generate the graphs we want
# NOTE: the first argument (name), must be unique; sets file name
genHTMLReportGraph ("connects",
"Number of connections attempted", "Connections/sec",
\@protocolsAll, "Try", ["conn" ]);
genHTMLReportGraph ("connections",
"Total connections", "Connections",
\@protocolsAll, "", ["connections" ]);
genHTMLReportGraph ("errors",
"Number of connection errors", "Errors/sec",
\@protocolsAll, "Error", ["conn", "banner", "login", "logout" ]);
genHTMLReportGraph ("retrieves",
"Number of messages read", "Messages/sec",
\@protocolsAll, "Try", ["retrieve" ]);
genHTMLReportGraph ("submits",
"Number of messages written", "Messages/sec",
\@protocolsAll, "Try", ["submit" ]);
genHTMLReportGraph ("commands",
"Protocol commands", "Commands/sec",
\@protocolsAll, "Try", ["cmd" ]);
genHTMLReportGraph ("readBytes",
"Bytes read", "Bytes/sec",
\@protocolsAll, "BytesR", ["login", "banner", "cmd", "retrieve", "submit", "logout" ]);
genHTMLReportGraph ("writeBytes",
"Bytes written", "Bytes/sec",
\@protocolsAll, "BytesW", ["login", "banner", "cmd", "retrieve", "submit", "logout" ]);
genHTMLReportGraph ("msgTime",
"Message transfer time", "Seconds per message",
\@protocols, "Time", ["cmd", "submit", "retrieve" ]);
genHTMLReportGraph ("setupTime",
"Connection setup time", "Seconds per connection",
\@protocols, "Time", ["conn", "banner", "login" ]);
genHTMLReportGraph ("blocks",
"Number of mailstone blocks executed", "Blocks/sec",
\@protocolsAll, "", ["blocks" ]);
}
if ($params{ADDGRAPHS}) { # pick up additional graphs
my @graphs = ();
readWorkloadFile ($params{ADDGRAPHS}, \@graphs);
foreach $section (@graphs) {
next unless ($section->{sectionTitle} =~ /GRAPH/o);
my $name = $section->{sectionParams};
$name =~ s/name=\s*//; # strip off initial bit
my @varlist = split (/[\s,]+/, $section->{VARIABLES});
$graphCount++;
genHTMLReportGraph ($name, $section->{TITLE}, $section->{LABEL},
($section->{FIELD} =~ /Time/o)
? \@protocols : \@protocolsAll,
$section->{FIELD}, \@varlist);
}
}
genHTMLReportEnd();
return 1;

415
mstone/bin/setup.pl Normal file
Просмотреть файл

@ -0,0 +1,415 @@
#!/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
# 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>
# Jim Salter <jsalter@netscape.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.
#####################################################
# usage: setup.pl setup|cleanup|checktime|timesync -m machine_file
# message files are expected to be in ./data/ and end with ".msg"
print "Netscape Mailstone.\nCopyright (c) 1997-2000 Netscape Communications Corp.\n";
$mode = shift; # mode must be first
# this parses the command line for -m machinefile
# also sets many defaults
do 'args.pl'|| die $@;
parseArgs(); # parse command line
setConfigDefaults(); # setup RSH and RCP
$cpcmd = "cp"; # copy files... dir
$rmcmd = "rm -f"; # remove files...
die "Must specify workload file" unless (@workload);
# Add or change client machines
sub configClients {
print "\n You can enter multiple machines like this: host1,host2\n";
my @d = <bin/*/bin>;
if (@d) {
my @d2;
foreach (@d2 = @d) { s/^bin\/// }
foreach (@d = @d2) { s/\/bin$// }
print " These OS versions are available:\n@d\n";
}
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
my $arch = "default OS";
$arch = $section->{ARCH} if ($section->{ARCH});
print "\nWhat is the name of the client(s) for $arch [$slist]: ";
my $ans = <STDIN>; chomp $ans;
if ($ans) {
$ans =~ s/\s//g; # strip any whitespace
fileReplaceText ($params{WORKLOAD}, "<CLIENT", $slist, $ans);
}
}
while (1) {
print "\nWhat additional client(s) [none]: ";
my $ans = <STDIN>; chomp $ans;
last unless ($ans); # done
last if ($ans =~ /^none$/i);
$ans =~ s/\s//g; # strip any whitespace
my $block = "\n<CLIENT HOSTS=$ans>\n";
print "What OS type [default]: ";
my $ans = <STDIN>; chomp $ans;
$block .= " Arch\t$ans\n" if ($ans && !($ans =~ /^default$/i));
$block .= "</CLIENT>\n";
fileInsertAfter ($params{WORKLOAD}, "^</CLIENT>", $block);
}
}
# Create a user ldif file
sub configUserLdif {
my $name = "conf/$defaultSection->{SERVER}.ldif";
print "\nWhat file to you want to create [$name]? ";
$ans = <STDIN>; chomp $ans;
$name = $ans if ($ans);
my $mode = "users";
print "\nDo you want to create a broadcast account [y]? ";
$ans = <STDIN>;
$mode .= " broadcast" unless ($ans =~ /^n/i);
my $basedn = $defaultSection->{SERVER}; # pick a default
$basedn =~ s/^.*?\.//; # strip off before first dot
$basedn = "o=$basedn";
print "\nWhat is LDAP base DN [$basedn]? ";
$ans = <STDIN>; chomp $ans;
$basedn = $ans if ($ans);
my $args = $params{MAKEUSERSARGS};
print "\n Common additional makeusers arguments:\n";
print "\t-s storeName -x storeCount \tMultiple store partitions\n";
print "\t[-3|-4] \tConfigure for NSMS 3.x or 4.x\n";
print "Any extra arguments to makeusers [$args]? ";
$ans = <STDIN>; chomp $ans;
$args = $ans if ($ans);
$params{DEBUG} &&
print "perl/bin/perl -Ibin -- bin/makeusers.pl $mode -w $params{WORKLOAD} -b '$basedn' -o $name $args\n";
print "\nGenerating $name (this can take a while)\n";
system "perl/bin/perl -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";
}
# This uses a match pattern plus text to text replacements.
# Could make all changes and then write out new workload
# You would have to be carefull about sections with multi-line support.
sub configWorkload {
my $ans;
print "\nWhat is the name of the mail host [$defaultSection->{SERVER}]: ";
$ans = <STDIN>; chomp $ans;
if ($ans) {
fileReplaceText ($params{WORKLOAD},
"(SERVER|SMTPMAILFROM|ADDRESSFORMAT)",
$defaultSection->{SERVER}, $ans);
$defaultSection->{SERVER} = $ans; # needed for ldif generation
}
print "\nWhat is the user name pattern [$defaultSection->{LOGINFORMAT}]: ";
$ans = <STDIN>; chomp $ans;
if ($ans) {
fileReplaceText ($params{WORKLOAD},
"(LOGINFORMAT|ADDRESSFORMAT)",
$defaultSection->{LOGINFORMAT}, $ans);
$ans =~ s/%ld/0/; # create smtpMailFrom user
my $olduser = $defaultSection->{SMTPMAILFROM};
$olduser =~ s/@.*$//; # strip off after @
fileReplaceText ($params{WORKLOAD},
"SMTPMAILFROM",
$olduser, $ans);
}
print "\nWhat is the password pattern [$defaultSection->{PASSWDFORMAT}]: ";
$ans = <STDIN>; chomp $ans;
fileReplaceText ($params{WORKLOAD}, "PASSWDFORMAT",
$defaultSection->{PASSWDFORMAT}, $ans);
$defaultSection->{NUMLOGINS} = 100 unless ($defaultSection->{NUMLOGINS});
print "\nHow many users [$defaultSection->{NUMLOGINS}]: ";
$ans = <STDIN>; chomp $ans;
fileReplaceText ($params{WORKLOAD}, "(NUMADDRESSES|NUMLOGINS)",
$defaultSection->{NUMLOGINS}, $ans);
$defaultSection->{FIRSTLOGIN} = 0 unless ($defaultSection->{FIRSTLOGIN});
print "\nWhat is the first user number [$defaultSection->{FIRSTLOGIN}]: ";
$ans = <STDIN>; chomp $ans;
fileReplaceText ($params{WORKLOAD}, "(FIRSTADDRESS|FIRSTLOGIN)",
$defaultSection->{FIRSTLOGIN}, $ans);
unless ($params{NT}) {
configClients ();
}
print "\nDo you want to view the edited $params{WORKLOAD} [y]? ";
$ans = <STDIN>;
unless ($ans =~ /^n/i) {
print "Here is the edited $params{WORKLOAD}:\n\n";
fileShow ($params{WORKLOAD});
print "\n";
}
print "\nDo you want to generate a user LDIF file [y]? ";
$ans = <STDIN>;
unless ($ans =~ /^n/i) {
configUserLdif ();
}
}
# See if license file has been displayed
unless (-f ".license" ) {
fileShow ("LICENSE");
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;
close (LIC);
}
if ($mode =~ /config$/) { # re-run config
configWorkload ();
print "\nMake any additional changes to $params{WORKLOAD} and then re-run 'setup'\n";
exit 0;
} else { # check if configured
my $unconf = 0; # see if default values are in use
foreach $section (@workload) {
($section->{SERVER})
&& ($section->{SERVER} =~ /example\.com$/)
&& $unconf++;
($section->{SMTPMAILFROM})
&& ($section->{SMTPMAILFROM} =~ /example\.com$/)
&& $unconf++;
($section->{ADDRESSFORMAT})
&& ($section->{ADDRESSFORMAT} =~ /example\.com$/)
&& $unconf++;
last if ($unconf > 0);
}
if ($unconf > 0) {
print "Server has not been configured (example.com is an invalid address).\n";
print "Do you want to setup a simple configuration now [y]?";
my $ans = <STDIN>;
if ($ans =~ /^n/i) {
print "Re-run setup when you have edited the configuration.\n";
exit 0;
}
configWorkload ();
print "\nMake any additional changes to $params{WORKLOAD} and then re-run 'setup'\n";
exit 0;
}
}
if ($mode =~ /timesync$/) {
if ($params{NT}) {
print "Timesync has no effect on NT\n";
exit 0;
}
my ($sec, $min, $hour, $mday, $mon, $year) = localtime;
$mon += 1; # adjust from 0 based to std
$systime = sprintf ("%02d%02d%02d%02d%04d.%02d",
$mon, $mday, $hour, $min, 1900+$year, $sec);
} elsif ($mode =~ /checktime$/) {
if ($params{NT}) { # if running on NT, then only single client
print "Checktime not needed on NT\n";
exit 0;
}
mkdir ("$resultbase", 0775);
mkdir ("$tmpbase", 0775);
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
foreach $cli (split /[\s,]/, $slist) {
open MAKEIT, ">$tmpbase/$cli.tim";
close MAKEIT;
}
}
} elsif (($mode =~ /setup$/) || ($mode =~ /cleanup$/)) {
@msgs = <data/*.msg>;
foreach (@files = @msgs) { s/data\/// }
print "Found these message files:\n@files\n\n";
if ($params{NT}) { # handle NT localhost here
exit 0 if ($mode =~ /cleanup$/);
my $clipath = "bin/WINNT4.0/bin/mailclient.exe";
print "Copying $clipath and message files to $cli\n";
system "copy $clipath $params{TEMPDIR}";
foreach $f (@files) {
system "copy $f $params{TEMPDIR}";
}
exit 0; # without perl:fork, no more to do
}
}
# iterate over every client in the testbed, complete the cmd and rsh
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
foreach $cli (split /[\s,]/, $slist) {
my $rsh = ($section->{RSH}) ? $section->{RSH} : $params{RSH};
my $rcp = ($section->{RCP}) ? $section->{RCP} : $params{RCP};
my $tempdir;
if ($section->{TEMPDIR}) {
$tempdir = $section->{TEMPDIR};
} elsif ($params{TEMPDIR}) {
$tempdir = $params{TEMPDIR};
}
# most time critical first
if ($mode =~ /timesync$/) {
next if ($cli =~ /^localhost$/i); # dont reset our own time
# run all these in parallel to minimize skew
next if ($section->{ARCH} eq "NT4.0");
forkproc ($rsh, $cli, "date $systime");
}
elsif ($mode =~ /checktime$/) {
# run all these in parallel to minimize skew
forkproc ($rsh, $cli, ($section->{ARCH} eq "NT4.0")
? "time" : "date",
"/dev/null", "$tmpbase/$cli.tim");
}
elsif ($mode =~ /setup$/) {
my ($clibin) = split /\s/, (($section->{COMMAND})
? $section->{COMMAND}
: $params{CLIENTCOMMAND});
my $clipath = "bin/$clibin";
if ($section->{ARCH}) {
if (-x "bin/$section->{ARCH}/bin/$clibin") {
$clipath="bin/$section->{ARCH}/bin/$clibin";
} else {
print "Requested OS $section->{ARCH} $cli not found. Using default.\n";
}
}
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 ($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 ($section->{ARCH} eq "NT4.0"); # should never happen
print "Copying $clipath and message files to $rdir\n";
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";
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});
system (split (/\s+/, $rsh), $cli, $rcmd);
}
print "\n";
}
elsif ($mode =~ /cleanup$/) {
if ($params{DEBUG}) { # get debug files
print "Cleaning up debug files on $cli\n";
my $rcmd = ($section->{ARCH} eq "NT4.0") ? "DEL" : "$rmcmd";
$rmcmd .= " mstone-debug.[0-9]*";
$rcmd = "cd $tempdir; " . $rcmd if ($tempdir);
$rcmd =~ s/;/&&/g if ($section->{ARCH} eq "NT4.0");
if ($cli =~ /^localhost$/i) {
die "TEMPDIR must be set for 'localhost'\n"
unless ($tempdir);
system ($rcmd);
} else {
system (split (/\s+/, $rsh), $cli, $rcmd);
}
} else {
print "Cleaning $cli\n";
my $rcmd = ($section->{ARCH} eq "NT4.0") ? "DEL" : "$rmcmd";
$rcmd .= " $clibin @files";
$rcmd = "cd $tempdir; " . $rcmd if ($tempdir);
$rcmd =~ s/;/&&/g if ($section->{ARCH} eq "NT4.0");
if ($cli =~ /^localhost$/i) {
die "TEMPDIR must be set for 'localhost'\n"
unless ($tempdir);
system ($rcmd);
} else {
system (split (/\s+/, $rsh), $cli, $rcmd);
}
}
}
else {
die "Couldn't recognize mode $mode!\n";
}
}
}
# wait for children to finish
if (($mode =~ /timesync$/) || ($mode =~ /checktime$/)) {
$pid = wait();
while ($pid != -1) {
$pid = wait();
}
}
# Print the results of the time checks
if ($mode =~ /checktime$/) {
print "Time from each client:\n";
foreach $section (@workload) {
next unless ($section->{sectionTitle} =~ /CLIENT/o);
my $slist = $section->{sectionParams};
$slist =~ s/HOSTS=\s*//; # strip off initial bit
foreach $cli (split /[\s,]/, $slist) {
open TIMEFILE, "$tmpbase/$cli.tim"
|| warn "Counldn't open $tmpbase/$cli.tim\n";
printf "%32s: ", $cli;
while (<TIMEFILE>) { print; last;} # single line (2 on NT)
close(TIMEFILE);
unlink "$tmpbase/$cli.tim";
}
}
}

0
mstone/conf/general.wld Normal file
Просмотреть файл

10
mstone/conf/http.wld Normal file
Просмотреть файл

@ -0,0 +1,10 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical HTTP GETs
<include conf/general.wld>
<HTTP>
weight 100
numLoops 1
httpcommand GET /
</HTTP>

19
mstone/conf/imap.wld Normal file
Просмотреть файл

@ -0,0 +1,19 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical IMAP checks/reads
<include conf/general.wld>
<CONFIG> # test specific config
title IMAP reads
clientCount 100 # since IMAP has long sleeps, use lots of clients
</CONFIG>
<IMAP4>
weight 100
#leaveMailOnServer 1
idleTime 2s # time between login and first download check
loopDelay 5m # time between download checks
numLoops 10 # how many check to do before closing the connection
blockTime 2s # time between logout and next login (or other block)
</IMAP4>

15
mstone/conf/pop.wld Normal file
Просмотреть файл

@ -0,0 +1,15 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical POP checks/reads
<include conf/general.wld>
<CONFIG> # test specific config
title POP reads
clientCount 50
</CONFIG>
<POP3>
weight 100
numLoops 9999 # will close when messages run out
#leaveMailOnServer 1
</POP3>

Просмотреть файл

@ -0,0 +1,44 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Deliver mail using SMTP
# This can measure delivery rates for a specified message type.
# This also fills the store for POP or IMAP tests
<include conf/general.wld>
<CONFIG> # test specific config
title POP, IMAP, SMTP combined load
clientCount 100
</CONFIG>
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical SMTP delivery with 1K message size and restricted accounts
<SMTP HOSTS=client1>
file en-1k.msg
weight 100
#numAddresses 200
</SMTP>
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical POP checks/reads
<POP3 HOSTS=client2>
weight 100
#leaveMailOnServer 1
</POP3>
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical IMAP checks/reads
# IMAP maintains a connection (unlike POP or SMTP)
# for combined load tests, run it on separate client machines
<IMAP4 HOSTS=client3>
weight 100
idleTime 5
checkMailInterval 10
numLoops 1000
</IMAP4>

21
mstone/conf/popsmtp.wld Normal file
Просмотреть файл

@ -0,0 +1,21 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Deliver mail using SMTP
# This can measure delivery rates for a specified message type.
# This also fills the store for POP or IMAP tests
<include conf/general.wld>
<CONFIG> # test specific config
title POP reads with SMTP message deliveries
clientCount 50
</CONFIG>
<include conf/smtp1k.wld>
<include conf/smtp5k.wld>
<include conf/smtp17k.wld>
<POP3>
weight 100
#leaveMailOnServer 1
</POP3>

0
mstone/conf/sample.html Normal file
Просмотреть файл

276
mstone/conf/sample.wld Normal file
Просмотреть файл

@ -0,0 +1,276 @@
# MailStone workload configuration file
#
# Include other workload files like this:
# <include conf/morework.wld>
#
# See Also:
# smtp.wld - typical SMTP delivery test
# pop.wld - typical POP3 check/download test
# imap.wld - typical IMAP4 check/download test
######################################################################
# These sections discribe how the test is run:
# CONFIG, CLIENT, MONITOR, PRETEST, POSTTEST
# The <CONFIG> section defines test setup and report parameters
# Multiple <CONFIG> sections will be merged into a one.
# The equivalent command line switch is shown in parenthesis.
<CONFIG>
title POP reads # title for report and index (-b)
comments Netscape MSG4.1 # additional info at top of report (-n)
time 3m # test time (-t)
rampTime 20s # portion of test to start things (-r)
clientCount 12 # number of client connections (-l)
maxErrors 10000 # set an error abort limit
maxBlocks 50000 # stop after this many blocks
#sysConfig conf/mailhost.txt # Pull in config file (-s)
sysConfig \ # Inline config text
<PRE>\
<B> mailhost.example.com </B>\
Netscape Messaging Server 4.11\
Linux 2.2.5\
4x400Mhz Xeon (1Mb)\
2Gb RAM\
</PRE>
useGroups 1 # use group names instead of host names
telemetry 1 # log telemetry (for debugging)
# These usually dont need to be set. These are the defaults
GnuPlot gnuplot/gnuplot
RSH /usr/bin/rsh
# RSH /usr/bin/remsh # HP-UX uses this path
RCP /usr/bin/rcp
tempDir /var/tmp # client machine directory
chartWidth 640
chartHeight 480
clientCommand mailclient # CLIENT command to run
monitorCommand vmstat %f # MONITOR command to run
makeUsersArgs -4 # args to makeusers
</CONFIG>
# Each <Client> section defines one or more client machines
# Every machine in the section will run the same number of connections
# Note that there cannot be whitespace between the client hostnames
<CLIENT HOSTS=client1,client2>
arch Linux2.2_x86
maxClients 200
maxThreads 50
# the group is only used if "useGroups" is set
group A
command mailclient -m 100 # override the command to run
</CLIENT>
# Set a specific number of processes and threads
<CLIENT HOSTS=client3,client4>
arch SunOS5.6
processes 2
threads 10
# the group is only used if "useGroups" is set
group B
</CLIENT>
# Here is how to configure a WinNT client from a Unix mail master
# The NT rshd must interoperate with Unix rsh; allow redirection of
# stdin, stdout, and stderr; and must support binary file copies.
# Denicomp's wrshdnt has been used sucessfully. www.denicomp.com
<CLIENT HOSTS=winnt01>
Arch WINNT4.0
command mailclient.exe
tempDir c:\temp
</CLIENT>
# The PreTest sections will run before the test starts
<PRETEST HOSTS=mailhost.example.com>
# RSH rsh -l mailuser
command cd /usr/netscape/msg-mailhost; ./getconf
</PRETEST>
# Each <Monitor> section defines remote monitoring commands
# for one or more machines.
# Commands containing '%c' run to completion.
# Otherwise the command will be shutdown down
<MONITOR HOSTS=mailhost.example.com>
command vmstat,%f,%c
</MONITOR>
# The PostTest sections will run after the test completes
<POSTTEST HOSTS=mailhost.example.com>
command df
</POSTTEST>
######################################################################
# available protcols: SMTP, POP3, IMAP4
# (command names are not case sensitive)
#
# Time formats use suffixes of 's', 'm', 'h', 'd'
# for seconds, minutes, hours, days
# In account formats, "%ld" is replaced by user number
# These parameters apply to the protocol sections
# Command parameter applicable command Example
#-------------------------------------------------------------------
# server <ALL> mail.example.com
# portNum <ALL> 25
# (if no value is given, the default port for that service is used)
#
# weight <ALL> 20
#
# loginFormat <ALL> test%ld
# %ld=address %ld=domain
# firstLogin <ALL> 0
# numLogins <ALL> 2000
# sequentialLogins <ALL> 1
# passwdFormat <ALL> netscape
#
# addressFormat <ALL> test%ld@mail.example%ld.com
# %ld=address %ld=domain
# firstAddress <ALL> 0
# numAddresses <ALL> 2000
# sequentialAddresses <ALL> 1
#
# numDomains <ALL> 3
# firstDomain <ALL> 0
# sequentialDomains <ALL> 1
#
# idleTime <ALL> 5m
# numLoops <ALL> 200
# loopDelay <ALL> 1m
# blockTime <ALL> 5m
#
# numRecips SMTP 3
# smtpMailFrom SMTP mailstone@mail.example.com
# file SMTP en-3k.msg
# useEHLO SMTP 1 (default is HELO)
# useAUTHLOGIN SMTP 1 (no AUTHLOGIN by default)
#
# leaveMailOnServer POP3,IMAP4 1
# leaveMailUnSeen IMAP4 1
# The <Default> section sets command block defaults
# Multiple <Default> sections will be merged into one
<DEFAULT>
server mailhost.example.com
smtpMailFrom mailhost0@mailhost.example.com
addressFormat mailhost%ld@mailhost.example.com
loginFormat mailhost%ld
passwdFormat netscape
numLogins 1000
numAddresses 1000
</DEFAULT>
# Note: empty host list means all hosts
<SMTP>
file en-1k.msg
weight 10
numAddresses 200
</SMTP>
<include conf/smtp17.wld>
# Note: the host name must be the same as specified in the CLIENT section
<POP3 HOSTS=client1,client2>
weight 10
#leaveMailOnServer 1
</POP3>
<IMAP4 HOSTS=client3>
idleTime 300
#weight 15
</IMAP4>
######################################################################
# These sections are used to generate the right graphs for the test
# This is the built in defaults
<GRAPH name=connects>
title Number of connections attempted
label Connections/sec
variables conn
field Try
</GRAPH>
<GRAPH name=connections>
title Total connections
label Connections
variables connections
</GRAPH>
<GRAPH name=connErrors>
title Number of connection errors
label Errors/sec
variables conn, banner, login, logout
field Error
</GRAPH>
<GRAPH name=msgErrors>
title Number of command/message errors
label Errors/sec
variables cmd, submit, retrieve
field Error
</GRAPH>
<GRAPH name=retrieves>
Title Number of messages read
label Messages/sec
variables retrieve
field Try
</GRAPH>
<GRAPH name=submits>
title Number of messages written
label Messages/sec
variables submit
field Try
</GRAPH>
<GRAPH name=commands>
title Number of commands sent
label Commands/sec
variables cmd
field Try
</GRAPH>
<GRAPH name=readBytes>
title Bytes read
label Bytes/sec
variables login, banner, cmd, retrieve, submit, logout
field BytesR
</GRAPH>
<GRAPH name=writeBytes>
title Bytes written
label Bytes/sec
variables login, banner, cmd, retrieve, submit, logout
field BytesW
</GRAPH>
<GRAPH name=msgTime>
title Message transfer time
label Seconds per message
variables cmd, submit, retrieve
field Time
</GRAPH>
<GRAPH name=setupTime>
Title Connection setup time
label Seconds per connection
variables conn, banner, login
field Time
</GRAPH>
<GRAPH name=blocks>
title Number of mailstone blocks executed
label Blocks/sec
variables blocks
# this is a scalar. No "field" needed/allowed
</GRAPH>

16
mstone/conf/smtp.wld Normal file
Просмотреть файл

@ -0,0 +1,16 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Deliver mail using SMTP
# This can measure delivery rates for a specified message type.
# This also fills the store for POP or IMAP tests
<include conf/general.wld>
<CONFIG> # test specific config
title SMTP message deliveries
clientCount 20
</CONFIG>
# if we include more than one, we get a distribution of all sizes
<include conf/smtp1k.wld>
<include conf/smtp5k.wld>
<include conf/smtp17k.wld>

0
mstone/conf/smtp17k.wld Normal file
Просмотреть файл

0
mstone/conf/smtp1k.wld Normal file
Просмотреть файл

0
mstone/conf/smtp5k.wld Normal file
Просмотреть файл

209
mstone/conf/wmap.wld Normal file
Просмотреть файл

@ -0,0 +1,209 @@
# MailStone workload configuration file. See sample.wld for detailed usage
# Typical WMAP checks/reads
<include conf/general.wld>
<CONFIG> # test specific config
title WMAP reads
clientCount 1 # since WMAP has long sleeps, use lots of clients
</CONFIG>
<DEFAULT>
# leaveMailOnServer 1
file en-1k.msg
#numAddresses 200
numRecips 1
idleTime 2s # time between login and first download check
loopDelay 5m # time between download checks
numLoops 10 # how many check to do before closing the connection
blockTime 2s # time between logout and next login (or other block)
</DEFAULT>
# This version pulls in everything (no caching)
<WMAP>
weight 20
# %s=referhost %s=host %d=content-length
wmapClientHeader "\
Referer: http://%s/\r\n\
Connection: Keep-Alive\r\n\
User-Agent: Mozilla/4.7 [en] (WinNT; U)\r\n\
Host: %s\r\n\
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n\
Accept-Encoding: gzip\r\n\
Accept-Language: en\r\n\
Accept-Charset: iso-8859-1,*,utf-8\r\n"
wmapBannerCmds "GET / HTTP/1.0"
wmapBannerCmds "GET /imx/N24b.gif HTTP/1.0"
wmapLoginCmd "POST /login.msc HTTP/1.0"
# %s=user %s=password
wmapLoginData "user=%s&password=%s"
# %s=sid
# (this one is done automatically from the redirect URL)
# wmapInboxCmds "GET /en/mail.html?sid=%s&\
#lang=en&host=http://toad.mcom.com/&cert=false HTTP/1.0"
wmapInboxCmds "GET /util.js HTTP/1.0"
wmapInboxCmds "GET /en/i18n.js HTTP/1.0"
wmapInboxCmds "GET /main.js HTTP/1.0"
wmapInboxCmds "GET /frame.html HTTP/1.0"
wmapInboxCmds "GET /cfg.msc?sid=%s&security=false HTTP/1.0"
wmapInboxCmds "GET /mbox_fs.html HTTP/1.0"
wmapInboxCmds "GET /imx/N16.gif HTTP/1.0"
wmapInboxCmds "GET /imx/spacer.gif HTTP/1.0"
wmapInboxCmds "GET /imx/pull.gif HTTP/1.0"
wmapInboxCmds "GET /imx/compose.gif HTTP/1.0"
wmapInboxCmds "GET /imx/search.gif HTTP/1.0"
wmapInboxCmds "GET /imx/divider.gif HTTP/1.0"
wmapInboxCmds "GET /imx/trash.gif HTTP/1.0"
wmapInboxCmds "GET /imx/read.gif HTTP/1.0"
wmapInboxCmds "GET /imx/sort_dn.gif HTTP/1.0"
wmapInboxCmds "GET /imx/high-0.gif HTTP/1.0"
wmapInboxCmds "GET /imx/read-1.gif HTTP/1.0"
# %s=sid
wmapCheckCmds "GET /mbox.msc?sid=%s&security=false&mbox=INBOX&\
start=-9999&count=9999&date=true&srch= HTTP/1.0"
# %s=sid, %d=message uid
wmapMsgReadCmds "GET /msg.msc?sid=%s&security=false&mbox=INBOX&\
uid=13&process=js,link,target,html,binhex&maxtext=30720 HTTP/1.0"
wmapMsgReadCmds "GET /msg_fs.html HTTP/1.0"
wmapMsgReadCmds "GET /reply.gif HTTP/1.0"
wmapMsgReadCmds "GET /reply_all.gif HTTP/1.0"
wmapMsgReadCmds "GET /forward.gif HTTP/1.0"
wmapMsgReadCmds "GET /prev-0.gif HTTP/1.0"
wmapMsgReadCmds "GET /all-0.gif HTTP/1.0"
wmapMsgReadCmds "GET /next-1.gif HTTP/1.0"
# %s=sid
#TODO wmapMsgDeleteCmds "GET / HTTP/1.0"
# %s=sid
#TODO wmapMsgComposeCmds "GET / HTTP/1.0"
# %s=sid
#TODO wmapMsgReplyCmds "GET / HTTP/1.0"
# %s=sid
#TODO wmapMsgReplyallCmds "GET / HTTP/1.0"
# %s=sid
#TODO wmapMsgForwardCmds "GET / HTTP/1.0"
# %s=sid
wmapMsgWriteCmds "GET / HTTP/1.0"
# %s=sid
wmapLogoutCmds "GET /cmd.msc?sid=%s&security=false&mbox=&cmd=logout HTTP/1.0"
</WMAP>
# This version assumes all static URLs are cached
<WMAP>
weight 80
# %s=referhost %s=host %d=content-length
wmapClientHeader "\
Referer: http://%s/\r\n\
Connection: Keep-Alive\r\n\
User-Agent: Mozilla/4.7 [en] (WinNT; U)\r\n\
Host: %s\r\n\
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n\
Accept-Encoding: gzip\r\n\
Accept-Language: en\r\n\
Accept-Charset: iso-8859-1,*,utf-8\r\n"
wmapBannerCmds "GET / HTTP/1.0"
wmapLoginCmd "POST /login.msc HTTP/1.0"
# %s=user %s=password
wmapLoginData "user=%s&password=%s"
# %s=sid
# (this one is done automatically from the redirect URL)
# wmapInboxCmds "GET /en/mail.html?sid=%s&\
#lang=en&host=http://toad.mcom.com/&cert=false HTTP/1.0"
wmapInboxCmds "GET /cfg.msc?sid=%s&security=false HTTP/1.0"
# %s=sid
wmapCheckCmds "GET /mbox.msc?sid=%s&security=false&mbox=INBOX&\
start=-9999&count=9999&date=true&srch= HTTP/1.0"
# %s=sid, %d=message uid
wmapMsgReadCmds "GET /msg.msc?sid=%s&security=false&mbox=INBOX&\
uid=13&process=js,link,target,html,binhex&maxtext=30720 HTTP/1.0"
# %s=sid
wmapMsgWriteCmds "GET / HTTP/1.0"
# %s=sid
wmapLogoutCmds "GET /cmd.msc?sid=%s&security=false&mbox=&cmd=logout HTTP/1.0"
</WMAP>
########################################################################
#
# Typical Communicator 4.7 to Messenger Express 4.1 dataflow
# High level requests (as seen using Network Monitor) and client [port] numbers
#
### Login
#
# GET /
# (gets login screen)
# GET /imx/N24b.gif
# (gets a gif as part of the screen)
# POST /login.msc
# Content-type: application/x-www-form-urlencoded
# user=x&password=x
# (performs the login, gets a Location: redirect with session ID)
# Location: http://mailhost/en/mail.html?sid=ebp32po0bt9u95rh&lang=en&host=http://mailhost/&cert=false
#
### INBOX Listing
#
# (first fetch the redirect url)
# GET /en/mail.html?sid=ebp32po0bt9u95rh&lang=en&host=http://mailhost/&cert=false
# (gets the inbox screen)
# GET /util.js
# GET /en/i18n.js
# GET /main.js
# GET /frame.html
# GET /frame.html
# GET /frame.html
# GET /cfg.msc?sid=ebp32po0bt9u95rh&security=false
# GET /frame.html
# GET /frame.html
#
# GET /mbox.msc?sid=ebp32po0bt9u95rh&security=false&mbox=INBOX&start=-9999&count=9999&date=true&srch=
# GET /mbox_fs.html
# GET /imx/N16.gif
# GET /imx/spacer.gif
# GET /imx/pull.gif
# GET /imx/compose.gif
# GET /imx/divider.gif
# GET /imx/trash.gif
# GET /imx/search.gif
# GET /imx/read.gif
# GET /imx/sort_dn.gif
# GET /imx/high-0.gif
# GET /imx/read-1.gif
#
### Reading a message
#
# GET /msg.msc?sid=ebp32po0bt9u95rh&security=false&mbox=INBOX&uid=13&process=js,link,target,html,binhex&maxtext=30720
# GET /msg_fs.html
# GET /imx/reply.gif
# GET /imx/reply_all.gif
# GET /imx/forward.gif
# GET /imx/prev-0.gif
# GET /imx/all-0.gif
# GET /imx/next-1.gif
#
### Logout
#
# GET /cmd.msc?sid=ebp32po0bt9u95rh&security=false&mbox=&cmd=logout
#
########################################################################

345
mstone/data/en-17k.msg Normal file
Просмотреть файл

@ -0,0 +1,345 @@
From: mailstone
To: test0
Message-ID: <12345678.123@nowhere>
Date: Fri, 10 Jul 1999 00:00:00 -0800
Subject: benchmark message
X-Accept-Language: en
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789

24
mstone/data/en-1k.msg Normal file
Просмотреть файл

@ -0,0 +1,24 @@
From: mailstone
To: test0
Message-ID: <12345678.123@nowhere>
Date: Fri, 10 Jul 1999 00:00:00 -0800
Subject: benchmark message
X-Accept-Language: en
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789

409
mstone/data/en-20k.msg Normal file
Просмотреть файл

@ -0,0 +1,409 @@
From: mailstone
To: test0
Message-ID: <12345678.123@nowhere>
Date: Fri, 10 Jul 1999 00:00:00 -0800
Subject: benchmark message
X-Accept-Language: en
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789

648
mstone/data/en-32k.msg Normal file
Просмотреть файл

@ -0,0 +1,648 @@
From: mailstone
To: test0
Message-ID: <12345678.123@nowhere>
Date: Fri, 10 Jul 1999 00:00:00 -0800
Subject: benchmark message
X-Accept-Language: en
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789

65
mstone/data/en-3k.msg Normal file
Просмотреть файл

@ -0,0 +1,65 @@
From: mailstone
To: test0
Message-ID: <12345678.123@nowhere>
Date: Fri, 10 Jul 1999 00:00:00 -0800
Subject: benchmark message
X-Accept-Language: en
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789

107
mstone/data/en-5k.msg Normal file
Просмотреть файл

@ -0,0 +1,107 @@
From: mailstone
To: test0
Message-ID: <12345678.123@nowhere>
Date: Fri, 10 Jul 1999 00:00:00 -0800
Subject: benchmark message
X-Accept-Language: en
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789
01234567890123456789012345678901234567890123456789

Просмотреть файл

0
mstone/doc/mstone.fm Normal file
Просмотреть файл

0
mstone/doc/next.gif Normal file
Просмотреть файл

0
mstone/doc/prev.gif Normal file
Просмотреть файл

0
mstone/doc/stone01.gif Normal file
Просмотреть файл

0
mstone/doc/stone02.gif Normal file
Просмотреть файл

0
mstone/doc/stone03.gif Normal file
Просмотреть файл

0
mstone/doc/trans.gif Normal file
Просмотреть файл

0
mstone/doc/up.gif Normal file
Просмотреть файл

0
mstone/mailstone.dsp Normal file
Просмотреть файл

0
mstone/mailstone.dsw Normal file
Просмотреть файл

0
mstone/mailstone.mak Normal file
Просмотреть файл

0
mstone/man/man1/setup.1 Normal file
Просмотреть файл

77
mstone/mstone Executable file
Просмотреть файл

@ -0,0 +1,77 @@
#!/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.
#####################################################
# This just runs the right test with the right path to perl
# Usage: mstone testname
if [ -z "$1" -o "$1" = "-h" -o "$1" = "--help" ] ; then
echo "Usage: $0 testname [arguments]"
echo "Common arguments:"
echo " -t time Test time. s=seconds, m=minutes, h=hours"
echo " -r ramp_time Connection ramp up time. s=seconds, m=..."
echo " -l load Number of test clients to use."
echo " -b 'banner' Test description banner."
echo " -n 'notes' Test notes."
echo "Example:"
echo " ./mstone pop -t 10m -r 90s -l 24 -b 'Pop reads (full store)'"
exit 1
fi
testcase=$1 # get testname
shift
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 [ -f $testcase ] ; then # if they gave us the full path
testfile=$testcase
else
[ -f conf/$testcase.wld ] && testfile="conf/$testcase.wld"
[ -f conf/$testcase.pl ] && testfile="conf/$testcase.pl"
fi
extra=""
if [ `uname -s` = HP-UX ] ; then # HP uses remsh for remote exec
extra="RSH=/usr/bin/remsh $extra"
fi
if [ -n "`echo $testfile | grep '\.wld$'`" ] ; then
exec perl/bin/perl -Ibin -- bin/mailmaster.pl $extra -w $testfile "$@"
elif [ -n "`echo $testfile | grep '\.pl$'`" ] ; then # BACK COMPAT 4.1
exec perl/bin/perl -Ibin -- $testfile $extra "$@"
fi
echo "File $testcase is not a workload file"
exit 1;

0
mstone/mstone.bat Executable file
Просмотреть файл

138
mstone/nsarch Executable file
Просмотреть файл

@ -0,0 +1,138 @@
#!/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" = "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

0
mstone/process Executable file
Просмотреть файл

0
mstone/process.bat Executable file
Просмотреть файл

0
mstone/setup Executable file
Просмотреть файл

0
mstone/setup.bat Executable file
Просмотреть файл

515
mstone/src/Makefile Normal file
Просмотреть файл

@ -0,0 +1,515 @@
# Makefile for mailstone
# This should be run using 'gmake'
########################################################################
PRODUCT = mailstone
ARCH := $(shell uname -s)
# These normally get overridden on the command line from ../Makefile
BUILD_VARIANT=debug
ifeq ($(BUILD_VARIANT), debug)
BUILD_TYPE = DEBUG
OBJDIR_TAG = _DBG
else
BUILD_TYPE = RELEASE
OBJDIR_TAG = _OPT
endif
ifeq ("$(OBJDIR)", "")
ifeq ($(ARCH), WINNT)
NSARCH := WIN32
else
NSARCH := $(shell ../nsarch)
endif
OBJDIR = ../build/$(NSARCH)$(OBJDIR_TAG).OBJ
PKGDIR = ../build/package/$(NSARCH)$(OBJDIR_TAG).OBJ
endif
########################################################################
# setup OS specific compilers and options
CC = cc
AR = ar
INCLUDES = -I$(OBJDIR)
REL_OS_CFLAGS = -O
REL_OS_LFLAGS =
DBG_OS_CFLAGS = -g -D_DEBUG
DBG_OS_LFLAGS =
LIBS = -lm
OBJ_SUFFIX = o
LIB_SUFFIX = a
EXE_SUFFIX =
LIBGD_DIR = gd1.3
GNUPLOT_DIR = gnuplot-3.7
PERL_DIR = perl5.005_03
PERL_REV = 5.00503
PERL5_IMPORT = /share/builds/components/perl5
ECHO = /bin/echo
ifeq ($(ARCH), WINNT)
CC = cl
OSDEFS = -DWIN32 -D_WIN32
LIBS = wsock32.lib libcmt.lib msvcrt.lib
REL_OS_CFLAGS =
REL_OS_LINKFLAGS = /link
DBG_OS_CFLAGS = -Od -Zi
DBG_OS_LINKFLAGS = /link /debug:full
OBJ_SUFFIX = obj
LIB_SUFFIX = .lib
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
PERL5_IMPORT = c:/perl/$(PERL_REV)/
PERL_FILES = $(PERL_DIR)/Artistic
PERL_BIN_FILES = \
$(PERL5_IMPORT)/bin/$(PERL_OS)/perl$(EXE_SUFFIX)
$(PERL5_IMPORT)/bin/$(PERL_OS)/perl$(DLL_SUFFIX) \
PERL_LIB_FILES = $(PERL5_IMPORT)/lib/*.pm $(PERL5_IMPORT)/lib/*.pl
PERL_LIB_OS_FILES = $(PERL5_IMPORT)/lib/$(PERL_OS)/*.pm
# PERL_FILES = $(PERL5_IMPORT)/artistic $(PERL5_IMPORT)/WINNT-perl5/perl.exe \
# $(PERL5_IMPORT)/WINNT-perl5/perl300.dll
endif
ifeq ($(ARCH), IRIX64)
ARCH = IRIX
endif
ifeq ($(ARCH), IRIX)
# 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
# PERL_FILES = $(PERL5_IMPORT)/artistic $(PERL5_IMPORT)/IRIX-perl5/perl5.005_02/perl
LIBS = -lm -lpthread
# OS specific flags for perl Configure
PERL_OS_CONFIGURE = -Dnm=/usr/bin/nm -Dar=/usr/bin/ar
PERL_OS = IP27-irix
endif
ifeq ($(ARCH), OSF1)
# 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
OSDEFS = -D__OSF1__ -DHAVE_SELECT_H -DHAVE_WAIT_H -DUSE_PTHREADS -DUSE_LRAND48_R
# PERL_FILES = $(PERL5_IMPORT)/artistic $(PERL5_IMPORT)/OSF1-perl5/perl5.005_2/perl
LIBS = -lm -lpthread
PERL_OS = alpha-dec_osf
endif
ifeq ($(ARCH), AIX)
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
# PERL_FILES = $(PERL5_IMPORT)/artistic $(PERL5_IMPORT)/AIX-perl5/perl5.005_2/perl
LIBS = -lm #-lpthread
PERL_OS = aix
endif
ifeq ($(ARCH), HP-UX)
CC = /usr/bin/cc
# 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
# PERL_FILES = $(PERL5_IMPORT)/artistic $(PERL5_IMPORT)/HPUX-perl5/perl5.005_02/perl
LIBS = -lm -lpthread
PERL_OS = PA-RISC2.0
endif
ifeq ($(ARCH), SunOS)
# 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
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 -lpthread
# PERL_FILES = $(PERL5_IMPORT)/artistic $(PERL5_IMPORT)/SOLARIS-perl5/perl5.005_02/perl
PERL_OS = sun4-solaris
endif
ifeq ($(ARCH), Linux)
# Linux 2.1 kernels and above
CC = /usr/bin/gcc # gcc 2.7.2.3
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
# PERL_FILES = $(PERL5_IMPORT)/artistic $(PERL5_IMPORT)/Linux2.1-perl5/perl
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 ($(BUILD_TYPE), DEBUG)
OS_CFLAGS = $(DBG_OS_CFLAGS) -D_DEBUG
OS_LINKFLAGS = $(DBG_OS_LINKFLAGS)
else
OS_CFLAGS = $(REL_OS_CFLAGS)
OS_LINKFLAGS = $(REL_OS_CFLAGS)
endif
CPPFLAGS =
CFLAGS = $(OS_CFLAGS)
###DEFINES = -DHAVE_CONFIG_H $(OSDEFS)
DEFINES = $(OSDEFS)
LDFLAGS =
BINDIR = ../bin
CP = cp
RM = rm -f
COMPILE = $(CC) $(CFLAGS) $(DEFINES) $(CPPFLAGS) $(INCLUDES)
GENRANDOBJS = genrand.$(OBJ_SUFFIX)
########################################################################
# what are we making
###all:: $(OBJDIR) libgd gnuplot mailclient
all:: $(OBJDIR) mailclient
########################################################################
.SUFFIXES: .c .$(OBJ_SUFFIX)
.SUFFIXES: .c .$(OBJ_SUFFIX)
.c.$(OBJ_SUFFIX):
ifeq ($(ARCH), WINNT)
$(COMPILE) -c -MT $< -Fo$(OBJDIR)/$@
else
$(COMPILE) -c $< -o $(OBJDIR)/$@
endif
$(OBJDIR)/%.$(OBJ_SUFFIX): %.c
ifeq ($(ARCH), WINNT)
$(COMPILE) -c -MT $< -Fo$(OBJDIR)/$*.$(OBJ_SUFFIX)
else
$(COMPILE) -c $< -o $(OBJDIR)/$*.$(OBJ_SUFFIX)
endif
$(OBJDIR):
ifeq ($(ARCH), WINNT)
mkdir $(OBJDIR)
else
[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
endif
########################################################################
# optional component libgd
ifneq ("$(LIBGD_DIR)", "")
LIBGD_OBJDIR = $(OBJDIR)/gd
LIBGD = $(LIBGD_OBJDIR)/libgd.$(LIB_SUFFIX)
GDDEMO = $(LIBGD_OBJDIR)/gddemo$(EXE_SUFFIX)
GIFTOGD = $(LIBGD_OBJDIR)/giftogd$(EXE_SUFFIX)
WEBGIF = $(LIBGD_OBJDIR)/webgif$(EXE_SUFFIX)
#LIBPATH += -L$(LIBGD_OBJDIR)
#INCLUDES += -I./$(LIBGD_DIR)
LIBGD_SRCS = gd.c gdfontt.c gdfonts.c gdfontmb.c gdfontl.c gdfontg.c
LIBGD_SRCS2 = $(addprefix $(LIBGD_DIR)/, $(LIBGD_SRCS))
LIBGD_OBJS = $(addprefix $(LIBGD_OBJDIR)/, $(LIBGD_SRCS:.c=.$(OBJ_SUFFIX)))
LIBGD_ALL = $(LIBGD_OBJDIR) $(LIBGD) $(GDDEMO) $(GIFTOGD) $(WEBGIF)
libgd:: $(LIBGD_ALL)
$(LIBGD_OBJDIR):
ifeq ($(ARCH), WINNT)
mkdir $(LIBGD_OBJDIR)
else
[ -d $(LIBGD_OBJDIR) ] || mkdir -p $(LIBGD_OBJDIR)
endif
$(LIBGD): $(LIBGD_OBJS)
@$(ECHO) "\n===== [`date`] making libgd...\n"
$(AR) rc $(LIBGD) $(LIBGD_OBJS)
cp $(LIBGD_DIR)/gd.h $(LIBGD_OBJDIR)
cp $(LIBGD_DIR)/demoin.gif $(LIBGD_OBJDIR)
cp $(LIBGD_DIR)/readme.txt $(LIBGD_OBJDIR)/gd.txt
cp $(LIBGD_DIR)/index.html $(LIBGD_OBJDIR)/gd.html
$(GDDEMO): $(LIBGD) $(LIBGD_OBJDIR)/gddemo.$(OBJ_SUFFIX)
$(COMPILE) $(LIBGD_OBJDIR)/gddemo.$(OBJ_SUFFIX) $(LIBPATH) $(LIBGD) $(LIBS) $(OS_LINKFLAGS) -o $(GDDEMO)
$(GIFTOGD): $(LIBGD) $(LIBGD_OBJDIR)/giftogd.$(OBJ_SUFFIX)
$(COMPILE) $(LIBGD_OBJDIR)/giftogd.$(OBJ_SUFFIX) $(LIBPATH) $(LIBGD) $(LIBS) $(OS_LINKFLAGS) -o $(GIFTOGD)
$(WEBGIF): $(LIBGD) $(LIBGD_OBJDIR)/webgif.$(OBJ_SUFFIX)
$(COMPILE) $(LIBGD_OBJDIR)/webgif.$(OBJ_SUFFIX) $(LIBPATH) $(LIBGD) $(LIBS) $(OS_LINKFLAGS) -o $(WEBGIF)
distclean::
$(RM) $(LIBGD) $(LIBGD_OBJS)
$(LIBGD_OBJDIR)/%.$(OBJ_SUFFIX): $(LIBGD_DIR)/%.c
ifeq ($(ARCH), WINNT)
$(COMPILE) -c -MT $< -Fo$(LIBGD_OBJDIR)/$*.$(OBJ_SUFFIX)
else
$(COMPILE) -c $< -o $(LIBGD_OBJDIR)/$*.$(OBJ_SUFFIX)
endif
endif
########################################################################
# optional component gnuplot (can use libgd)
ifneq ("$(GNUPLOT_DIR)", "")
GNUPLOT = gnuplot$(EXESUFFIX)
GNUPLOT_OBJDIR = $(OBJDIR)/gnuplot
GNUPLOT_TARGET = $(GNUPLOT_OBJDIR)/$(GNUPLOT)
GNUPLOT_HELP = $(GNUPLOT_OBJDIR)/gnuplot.gih
GNUPLOT_CONFIG_H = $(GNUPLOT_OBJDIR)/config.h
ifneq ("$(LIBGD_DIR)", "")
GNUPLOT_CONFIG_OPTS = --prefix=/opt/mailstone --with-gd=../../$(LIBGD_OBJDIR) --with-png=no --without-linux-vga
endif
GNUPLOT_ALL = $(GNUPLOT_OBJDIR) $(GNUPLOT_TARGET) $(GNUPLOT_HELP)
gnuplot:: $(GNUPLOT_ALL)
$(GNUPLOT_OBJDIR):
ifeq ($(ARCH), WINNT)
mkdir $(GNUPLOT_OBJDIR)
else
[ -d $(GNUPLOT_OBJDIR) ] || mkdir -p $(GNUPLOT_OBJDIR)
endif
$(GNUPLOT_TARGET): $(GNUPLOT_CONFIG_H)
@$(ECHO) "\n===== [`date`] making gnuplot...\n"
(cd $(GNUPLOT_OBJDIR); $(MAKE) MAKE=$(MAKE) all)
$(GNUPLOT_HELP):
cp $(GNUPLOT_DIR)/docs/gnuplot.1 $(GNUPLOT_OBJDIR)
cp $(GNUPLOT_DIR)/Copyright $(GNUPLOT_OBJDIR)
cp $(GNUPLOT_OBJDIR)/docs/gnuplot.gih $(GNUPLOT_HELP)
$(GNUPLOT_CONFIG_H):
@$(ECHO) "\n===== [`date`] making gnuplot config.h...\n"
(cd $(GNUPLOT_OBJDIR); CC="$(CC) $(CFLAGS)" ../../../src/$(GNUPLOT_DIR)/configure $(GNUPLOT_CONFIG_OPTS))
distclean::
[ ! -f $(GNUPLOT_OBJDIR)/Makefile ] || \
(cd $(GNUPLOT_OBJDIR); $(MAKE) MAKE=$(MAKE) distclean)
$(RM) $(GNUPLOT_TARGET) $(GNUPLOT_CONFIG_H)
$(GNUPLOT_OBJDIR)/%.$(OBJ_SUFFIX): $(GNUPLOT_DIR)/%.c
ifeq ($(ARCH), WINNT)
$(COMPILE) -c -MT $< -Fo$(GNUPLOT_OBJDIR)/$*.$(OBJ_SUFFIX)
else
$(COMPILE) -c $< -o $(GNUPLOT_OBJDIR)/$*.$(OBJ_SUFFIX)
endif
endif
########################################################################
# mailclient itself
STONE = $(OBJDIR)/mailclient$(EXE_SUFFIX)
STONESRCS = bench.c client.c errexit.c http.c imap4.c main.c \
parse.c pop3.c smtp.c sysdep.c timefunc.c wmap.c
STONEOBJS = $(addprefix $(OBJDIR)/, $(STONESRCS:.c=.$(OBJ_SUFFIX)) )
# mailclient currently depends on config.h as created by gnuplot
###mailclient:: gnuplot $(STONE)
mailclient:: $(STONE)
$(STONE): $(STONEOBJS) Makefile
@$(ECHO) "\n===== [`date`] making $(STONE)...\n"
$(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 Makefile
$(OBJDIR)/errexit.$(OBJ_SUFFIX): errexit.c bench.h sysdep.h Makefile
$(OBJDIR)/http.$(OBJ_SUFFIX): http.c bench.h pish.h sysdep.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
$(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
$(OBJDIR)/stats.$(OBJ_SUFFIX): stats.c bench.h sysdep.h Makefile
$(OBJDIR)/sysdep.$(OBJ_SUFFIX): sysdep.c bench.h sysdep.h Makefile
$(OBJDIR)/timefunc.$(OBJ_SUFFIX): timefunc.c bench.h sysdep.h Makefile
$(OBJDIR)/wmap.$(OBJ_SUFFIX): wmap.c bench.h sysdep.h Makefile
install: all
$(CP) $(STONE) $(BINDIR)
distclean:: clean
$(RM) -rf $(OBJDIR)
clean::
$(RM) $(STONEOBJS) $(STONE)
# use the higher-level makefile for most builds
debug::
@$(ECHO) "\n===== [`date`] making debug...\n"
(cd ..; $(MAKE) debug)
release::
@$(ECHO) "\n===== [`date`] making release...\n"
(cd ..; $(MAKE) release)
########################################################################
# optional component perl
PERL_OBJDIR = $(OBJDIR)/perl
PERL_PKGDIR = $(PKGDIR)/perl
###package:: $(PERL_PKGDIR) package-perl
$(PERL_PKGDIR):
ifeq ($(ARCH), WINNT)
mkdir $(PERL_PKGDIR)
mkdir $(PERL_PKGDIR)/bin
mkdir $(PERL_PKGDIR)/lib
mkdir $(PERL_PKGDIR)/lib/$(PERL_REV)
mkdir $(PERL_PKGDIR)/lib/$(PERL_REV)/$(PERL_OS)
else
[ -d $(PERL_PKGDIR)/bin ] || mkdir -p $(PERL_PKGDIR)/bin
[ -d $(PERL_PKGDIR)/lib ] || mkdir -p $(PERL_PKGDIR)/lib
# subdirs created by perl install
endif
ifeq ("$(PERL_FILES)", "")
# building our own perl
###all:: perl
all::
PERL_TARGET = $(PERL_OBJDIR)/perl
PERL_SRCSTAMP = $(PERL_OBJDIR)/perl_src.stamp
PERL_TESTSTAMP = $(PERL_OBJDIR)/perl_test.stamp
PERL_PKGSTAMP = $(PERL_OBJDIR)/perl_pkg.stamp
PERL_CONFIG_H = $(PERL_OBJDIR)/config.h
PERL_FINAL_PKGDIR = /opt/mailstone/perl
PERL_ADMIN = mailstone+perl@netscape.com
PERL_PAGER = /bin/more
perl:: $(PERL_OBJDIR) $(PERL_TARGET) $(PERL_TESTSTAMP)
$(PERL_OBJDIR):
ifeq ($(ARCH), WINNT)
mkdir $(PERL_OBJDIR)
else
[ -d $(PERL_OBJDIR) ] || mkdir -p $(PERL_OBJDIR)
endif
$(PERL_TARGET): $(PERL_CONFIG_H)
@$(ECHO) "\n===== [`date`] making perl...\n"
( cd $(PERL_OBJDIR); $(MAKE) MAKE=$(MAKE) )
@$(ECHO) "\n===== [`date`] making perl done.\n"
$(PERL_CONFIG_H): $(PERL_OBJDIR)/config.over
@$(ECHO) "\n===== [`date`] making perl config.h...\n"
(\
cd $(PERL_OBJDIR); \
rm -f config.sh makedir makedepend makeaperl config.h cflags \
Policy.sh Makefile writemain perl.exp perlmain.c makefile; \
$(ECHO) MAKE=$(MAKE) MAKEFLAGS=$(MAKEFLAGS); \
MAKEFLAGS= ; export MAKEFLAGS; \
sh Configure -Dprefix=$(PERL_FINAL_PKGDIR) \
-Uinstallusrbinperl -Uusethreads -Uusedl \
-Dcc="$(CC)" -Dmake=$(MAKE) \
-Dcf_email=$(PERL_ADMIN) \
-Dperladmin=$(PERL_ADMIN) -Dpager=$(PERL_PAGER) $(PERL_OS_CONFIGURE) -de ; \
)
$(PERL_OBJDIR)/config.over: $(PERL_SRCSTAMP)
@$(ECHO) "\n===== [`date`] making perl config.over...\n"
(\
perl_pkgdir=`pwd`/$(PERL_PKGDIR); \
cd $(PERL_OBJDIR); \
$(ECHO) "\
installprefix=$${perl_pkgdir}\n\
$(ECHO) \"overriding tmp install dir from \$$prefix to \$$installprefix\"\n\
test -d \$$installprefix || mkdir \$$installprefix\n\
test -d \$$installprefix/bin || mkdir \$$installprefix/bin\n\
installarchlib=\`$(ECHO) \$$installarchlib | sed \"s!\$$prefix!\$$installprefix!\"\`\n\
installbin=\`$(ECHO) \$$installbin | sed \"s!\$$prefix!\$$installprefix!\"\`\n\
installman1dir=\`$(ECHO) \$$installman1dir | sed \"s!\$$prefix!\$$installprefix!\"\`\n\
installman3dir=\`$(ECHO) \$$installman3dir | sed \"s!\$$prefix!\$$installprefix!\"\`\n\
installprivlib=\`$(ECHO) \$$installprivlib | sed \"s!\$$prefix!\$$installprefix!\"\`\n\
installscript=\`$(ECHO) \$$installscript | sed \"s!\$$prefix!\$$installprefix!\"\`\n\
installsitelib=\`$(ECHO) \$$installsitelib | sed \"s!\$$prefix!\$$installprefix!\"\`\n\
installsitearch=\`$(ECHO) \$$installsitearch | sed \"s!\$$prefix!\$$installprefix!\"\`" \
> config.over;\
)
$(PERL_SRCSTAMP): $(PERL_DIR)
@$(ECHO) "\n===== [`date`] making perl src links from $(PERL_DIR) to $(PERL_OBJDIR)...\n"
-rm -f $(PERL_SRCSTAMP)
[ -d $(PERL_OBJDIR) ] || mkdir -p $(PERL_OBJDIR)
-(\
perl_dir=`pwd`/$(PERL_DIR); \
cd $(PERL_OBJDIR); \
for i in `(cd $${perl_dir} && find . -type d -print)` ; do \
$(ECHO) "linking dir $$i ..."; \
[ -d $$i ] || mkdir $$i; \
for j in `(cd $${perl_dir}/$$i; echo *)` ; do \
[ -f $${perl_dir}/$$i/$$j -o -h $${perl_dir}/$$i/$$j ] && ( \
/bin/true || $(ECHO) " $$i/$$j"; \
ln -s $${perl_dir}/$$i/$$j $$i/$$j); \
done; \
done; \
)
touch $(PERL_SRCSTAMP)
@$(ECHO) "\n===== [`date`] making perl src links done...\n"
$(PERL_TESTSTAMP): $(PERL_TARGET)
@$(ECHO) "\n===== [`date`] making perl test-notty...\n"
-rm -f $(PERL_TESTSTAMP)
-( cd $(PERL_OBJDIR); $(MAKE) MAKE=$(MAKE) test-notty )
touch $(PERL_TESTSTAMP)
@$(ECHO) "\n===== [`date`] making perl test-notty done.\n"
package-perl:: $(PERL_PKGSTAMP)
$(PERL_PKGSTAMP):: $(PERL_TESTSTAMP)
@$(ECHO) "\n===== [`date`] making perl package ...\n"
-rm -f $(PERL_PKGSTAMP)
cp $(PERL_OBJDIR)/Artistic $(PERL_PKGDIR)
( cd $(PERL_OBJDIR); $(MAKE) MAKE=$(MAKE) install )
-rm -rf $(PERL_PKGDIR)/lib/$(PERL_REV)/*/CORE/
touch $(PERL_PKGSTAMP)
@$(ECHO) "\n===== [`date`] making perl package done.\n"
else # PERL_FILES
# importing a perl
package-perl:: $(PERL_PKGDIR) $(PERL_TARGET)
$(PERL_TARGET): $(PERL_FILES) $(PERL_BIN_FILES) $(PERL_LIB_FILES)
cp $(PERL_FILES) $(PERL_PKGDIR)/
cp $(PERL_BIN_FILES) $(PERL_PKGDIR)/bin/
cp $(PERL_LIB_FILES) $(PERL_PKGDIR)/lib/$(PERL_REV)/
cp $(PERL_LIB_OS_FILES) $(PERL_PKGDIR)/lib/$(PERL_REV)/$(PERL_OS)/
endif # PERL_FILES

0
mstone/src/README Normal file
Просмотреть файл

873
mstone/src/bench.c Normal file
Просмотреть файл

@ -0,0 +1,873 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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): Dan Christian <robodan@netscape.com>
* Marcel DePaolis <marcel@netcape.com>
* Mike Blakely
*
* 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.
*/
/*
bench.c has all the OS independent utilities.
*/
#include "bench.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)
* parameter: fd: file descriptor
* read_write: 0 --> read
* 1 --> write
* 2 --> read & write
* return: NON-Zero something is read
* 0 sth is wrong
*/
#define CHECK_READ 0x0
#define CHECK_WRITE 0x1
#define CHECK_RW 0x2
#define CHECK_ALL 0x3
#define CHECK_FOREVER 0x4
#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(int fd, int flags)
{
#ifdef _WIN32
return 0;
#else
struct pollfd pfd;
int timeleft;
int ret;
int timeouts = 0;
pfd.fd = fd;
pfd.events = POLLHUP;
if ((flags & CHECK_ALL) == CHECK_READ) {
pfd.events |= POLLIN;
} else if ((flags & CHECK_ALL) == CHECK_WRITE) {
pfd.events |= POLLOUT;
} else if ((flags & CHECK_ALL) == CHECK_RW) {
pfd.events |= (POLLIN | POLLOUT);
}
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;
}
/* error */
return 0;
#endif
}
int
retryRead(ptcx_t ptcx, SOCKET sock, char *buf, int count)
{
int ret;
int bytesread = 0;
D_PRINTF(debugfile, "retryRead(%d, %d (gf_timeexpired=%d))\n",
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)) {
D_PRINTF (debugfile, "retryRead waitReadable time/error\n");
strcpy (ptcx->errMsg, "waitReadable TIMEOUT<retryRead");
break;
}
ret = NETREAD(sock, buf, count);
if (ret < 0) {
if (errno == EINTR)
continue;
if (errno == EAGAIN) {
if (bytesread > 0)
break; /* return what we got so far */
if (waitReadable(sock)) {
continue;
}
}
if (bytesread == 0) {
bytesread = -1;
}
sprintf (ptcx->errMsg, "retryRead(sock=%d) IO error", sock);
break;
}
bytesread += ret;
buf += ret;
count -= ret;
break; /* return any good bytes */
}
D_PRINTF(debugfile, "retryRead(%d, %d)=%d\n", sock, count, bytesread);
return bytesread;
}
int
retryWrite(ptcx_t ptcx, SOCKET sock, char *buf, int count)
{
int ret;
int byteswritten = 0;
D_PRINTF(debugfile, "retryWrite(%d, %d)\n", sock, count);
while (count) {
if (gf_timeexpired >= EXIT_FAST) {
D_PRINTF (debugfile, "retryWrite gf_timeexpired\n");
strcpy (ptcx->errMsg, "read:timeout");
break;
}
ret = NETWRITE(sock, buf, count);
if (ret < 0) {
if (errno == EINTR)
continue;
if (errno == EAGAIN) {
if (waitWriteable(sock)) {
continue;
}
}
if (byteswritten == 0) {
byteswritten = -1;
}
sprintf (ptcx->errMsg,
"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, count, byteswritten);
return byteswritten;
}
int
readResponse(ptcx_t ptcx, SOCKET sock, char *buffer, int buflen)
{
/* read the server response and do nothing with it */
int totalbytesread = 0;
int resplen = 0;
int bytesread;
char *offset;
memset (buffer, 0, sizeof(buffer));
while (totalbytesread < buflen)
{
if (gf_timeexpired >= EXIT_FAST) {
D_PRINTF(debugfile,"readResponse() Time expired.\n");
break;
}
if ((bytesread = retryRead(ptcx, sock, buffer+totalbytesread,
buflen-totalbytesread)) <= 0) {
strcat (ptcx->errMsg, "<ReadResponse");
return -1;
}
totalbytesread += bytesread;
buffer[totalbytesread] = 0;
/* search for end of response (assume single line) */
if ((offset = strstr(buffer, "\n"))) {
resplen = offset - buffer + 1;
break;
} else if ((offset = strstr(buffer, "\r\n"))) {
resplen = offset - buffer + 2;
break;
}
}
D_PRINTF(debugfile, "Read from server: %s\n", buffer );
ptcx->bytesread += resplen;
return resplen;
}
/* expects pointers to buffers of these sizes */
/* char command[MAX_COMMAND_LEN] */
/* char response[MAX_RESPONSE_LEN] */
int
doCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen)
{
int ret;
if (response == NULL)
return -1;
memset(response, 0, resplen);
/* send the command already formatted */
if ((ret = sendCommand(ptcx, sock, command)) == -1) {
strcat (ptcx->errMsg, "<doCommandResponse");
return -1;
}
/* read server response line */
if ((ret = readResponse(ptcx, sock, response, resplen)) <= 0) {
strcat (ptcx->errMsg, "<doCommandResponse");
return -1;
}
return ret;
}
int
sendCommand(ptcx_t ptcx, SOCKET sock, char *command)
{
int writelen;
int sentbytes = 0;
int sent;
D_PRINTF(debugfile, "sendCommand(%s)\n", command );
writelen = strlen(command);
while (sentbytes < writelen) {
if ((sent = retryWrite(ptcx, sock, command + sentbytes,
writelen - sentbytes)) == -1) {
strcat (ptcx->errMsg, "<sendCommand");
return -1;
}
sentbytes += sent;
if (gf_timeexpired >= EXIT_FAST) {
D_PRINTF(debugfile,"sendCommand() Time expired.\n");
break;
}
}
ptcx->byteswritten += sentbytes;
return sentbytes;
}
/* assumes we already included the <CRLF>.<CRLF> at the end of message */
int
sendMessage(ptcx_t ptcx, SOCKET sock, char *message)
{
int writelen;
int sentbytes = 0;
int sent;
writelen = strlen(message);
D_PRINTF(debugfile, "Writing message to server: len=%d\n", writelen );
while (sentbytes < writelen) {
if ((sent = retryWrite(ptcx, sock, message + sentbytes,
writelen - sentbytes)) == -1) {
strcat (ptcx->errMsg, "<sendMessage");
return -1;
}
sentbytes += sent;
if (gf_timeexpired >= EXIT_FAST) {
D_PRINTF(debugfile,"sendMessage() Time expired.\n");
break;
}
}
ptcx->byteswritten += sentbytes;
return sentbytes;
}
/* This is how status messages are sent */
int
sendOutput(int fd, char *string)
{
int writelen;
int sentbytes = 0;
int sent;
/*D_PRINTF(stderr, "sendOutput(%d, %s)\n", fd, string );*/
writelen = strlen(string);
while (sentbytes < writelen) {
sent = OUTPUT_WRITE(fd, string + sentbytes, writelen - sentbytes);
if (sent == -1) {
if (errno == EINTR)
continue;
if (errno == EAGAIN) {
if (waitWriteableForever(fd))
continue;
else
returnerr(stderr,
"sendOutput(%d) - Got EAGAIN and fd not ready\n",
fd); /* has this ever happened? die??? */
}
return -1;
}
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> */
int
retrMsg(ptcx_t ptcx, char *buffer, int maxBytes, SOCKET sock)
{
int totalbytesread = 0;
int bytesread;
int sz;
char garbage[10000], *sp;
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;
}
bytesread = retryRead(ptcx, sock,
sp+totalbytesread, sz-totalbytesread);
/*D_PRINTF (stderr, "retrMsg: got %d bytes\n", bytesread);*/
if (bytesread <= 0) {
strcat (ptcx->errMsg, "<retrMsg");
return -1;
}
ptcx->bytesread += bytesread;
totalbytesread += bytesread;
sp[totalbytesread] = 0; /* terminate string */
if (NULL != strstr (sp, "\r\n.\r\n")) {
D_PRINTF (stderr, "retrMsg: saw terminating string\n");
break;
}
if (!strncmp (sp, "-ERR", 4)) { /* watch for error response */
trimEndWhite (sp);
sprintf (ptcx->errMsg, "retrMsg: ERROR response=[%.40s]", sp);
return -1;
}
if (!buffer && (totalbytesread > 5)) { /* reset our scratch buffer */
int i;
char *from, *to;
/* shuffle last 5 bytes to start */
from = sp + totalbytesread - 5;
to = garbage;
for (i=5; i > 0; --i)
*to++ = *from++;
totalbytesread = 5;
}
}
return totalbytesread;
}
/*
Record current time
*/
int
timeval_stamp(struct timeval *tv)
{
int rc;
rc = GETTIMEOFDAY(tv, NULL);
if (rc != 0) {
errexit(stderr, "Error from gettimeofday()\n");
}
return rc;
}
/*
This is the main event timing routine. This resets counters
Note that event timing cannot be nested.
*/
void
event_start(ptcx_t ptcx, event_timer_t *pevent)
{
ptcx->bytesread = 0;
ptcx->byteswritten = 0;
timeval_stamp(&ptcx->starttime);
}
/*
This ends an event and increments the counters
Multiple stops are no longer allowed. (broke min, max, and sum of t*t)
*/
void
event_stop(ptcx_t ptcx, event_timer_t *pevent)
{
struct timeval tv;
double t;
timeval_stamp(&tv); /* get the time */
if (gf_timeexpired >= EXIT_FAST) { /* if aborting run, ignore it */
return;
}
pevent->trys++; /* count try with time */
pevent->bytesread += ptcx->bytesread;
pevent->byteswritten += ptcx->byteswritten;
t = compdifftime_double(&tv, &ptcx->starttime); /* find time span */
pevent->elapsedtime += t;
pevent->elapsedtimesq += t * t;
if (t > pevent->maxtime) /* check max time */
pevent->maxtime = t;
/* this gets initialized to 0.0 */
if (!pevent->mintime || /* check min time */
((t > 0.0) && (t < pevent->mintime))) /* smallest non 0 time */
pevent->mintime = t;
}
/*
reset the event structure
*/
void
event_reset(event_timer_t *pevent)
{
memset(pevent, 0, sizeof(event_timer_t));
}
/*
Add pincr event into psum event
*/
void
event_sum(event_timer_t *psum, event_timer_t *pincr)
{
psum->trys += pincr->trys;
psum->errs += pincr->errs;
psum->bytesread += pincr->bytesread;
psum->byteswritten += pincr->byteswritten;
psum->elapsedtime += pincr->elapsedtime;
psum->elapsedtimesq += pincr->elapsedtimesq;
if (pincr->maxtime > psum->maxtime)
psum->maxtime = pincr->maxtime;
if (!psum->mintime ||
((pincr->mintime > 0.0) && (pincr->mintime < psum->mintime)))
psum->mintime = pincr->mintime;
}
/* Format string for every timer. Must match event_to_text */
const char *gs_eventToTextFormat = "Try+Error/BytesR+BytesW/Time[TimeMin,TimeMax]Time2";
/*
Output event into ebuf.
*/
char *
event_to_text(event_timer_t *pevent, char *ebuf)
{
/* these have to be sane to avoid overflowing the print buffer */
assert (pevent->bytesread < 1.0e20);
assert (pevent->byteswritten < 1.0e20);
assert (pevent->elapsedtime < 1.0e10);
assert (pevent->maxtime < 1.0e10);
assert (pevent->elapsedtimesq < 1.0e20);
if (pevent->elapsedtime) {
sprintf(ebuf, "%ld+%ld/%.0f+%.0f/%.6f[%.6f,%.6f]%.6f",
pevent->trys, pevent->errs,
pevent->bytesread, pevent->byteswritten,
pevent->elapsedtime,
pevent->mintime,
pevent->maxtime,
pevent->elapsedtimesq);
} else { /* trim extra 0s for simple case*/
sprintf(ebuf, "%ld+%ld/%.0f+%.0f/0.0[0.0,0.0]0.0",
pevent->trys, pevent->errs,
pevent->bytesread, pevent->byteswritten);
}
return ebuf;
}
/*
Given the last value we returned, return the next sequential or random value
If the initial value is out of the range, a valid number will be returned.
*/
unsigned long
rangeNext (range_t *range, unsigned long last)
{
unsigned long n;
assert (range != NULL);
if (range->span == 0) /* empty range (span = 0) */
return range->first;
if (range->sequential > 0) { /* incrementing sequential */
n = last + 1;
} else if (range->sequential < 0) { /* decrementing sequential */
n = last - 1;
} else { /* random */
n = range->first + (RANDOM() % range->span);
assert ((n >= range->first) && (n <= range->last));
}
/* check range */
if (n > range->last) n = range->first;
if (n < range->first) n = range->last;
return n;
}
/*
Setup range given a first and last valid values (inclusive)
Direction: + incrementing, 0 random, - decrementing
If first and last are reversed, it will adjust accordingly
*/
void
rangeSetFirstLast (range_t *range,
unsigned long first,
unsigned long last,
int dir)
{
assert (range != NULL);
if (last > first) {
range->first = first;
range->last = last;
range->sequential = dir;
} else {
range->first = last;
range->last = first;
range->sequential = -dir;
}
range->span = range->last - range->first;
}
/*
Setup range given a first valid value (inclusive) and number (1..)
Direction: + incrementing, 0 random, - decrementing
*/
void
rangeSetFirstCount (range_t *range,
unsigned long first,
unsigned long num,
int dir)
{
assert (range != NULL);
if (num > 0) --num; /* adjust to internal notation */
range->first = first;
range->span = num;
range->last = range->first + range->span;
range->sequential = dir;
}
/*
Given a specified range, split it based on process and thread
*/
void
rangeSplit (range_t *whole, range_t *sub, int pnum, int tnum)
{
unsigned long perproc, first, count;
if (!whole->sequential) { /* just copy it */
sub->first = whole->first;
sub->last = whole->last;
sub->span = whole->span;
sub->sequential = whole->sequential;
return;
}
/* To avoid cumulative rounding errors,
the 0th process/thread rounds up, all others round down */
perproc = (pnum > 0)
? (whole->span+1) / gn_numprocs
: (whole->span+1 + gn_numprocs - 1) / gn_numprocs;
if (perproc <= 0) perproc = 1; /* in case logins > processes */
if (gn_numthreads > 0) {
unsigned long perthread;
perthread = (tnum > 0)
? perproc / gn_numthreads
: (perproc + gn_numthreads - 1) / gn_numthreads;
if (perthread <= 0) perthread = 1; /* in case logins > threads */
first = whole->first + (perproc * pnum) + (perthread * tnum);
count = perthread;
} else {
first = whole->first + (perproc * pnum);
count = perproc;
}
/* If logins > processes*threads, we have to wrap the space */
while (first >= (whole->first + whole->span+1)) {
first -= whole->span+1;
}
assert (first >= whole->first);
rangeSetFirstCount (sub, first, count, whole->sequential);
}
/*
clear protocol independ parts of cmd_stats_t
*/
void
cmdStatsInit (cmd_stats_t *p)
{
assert (NULL != p);
p->totalerrs = 0;
p->totalcommands = 0;
event_reset (&p->combined);
event_reset (&p->idle);
}
void
stats_init(stats_t *p)
{
memset(p, 0, sizeof(*p));
}
/*
Given a buffer, trim tailing CR-NL and whitespace from it
Moves 0 terminator to exclude extra portion.
*/
void
trimEndWhite (char *buff)
{
char *cp;
if (!buff) return;
for (cp = buff; *cp; ++cp); /* find the end */
while (cp > buff) {
--cp;
if ((*cp != '\n') && (*cp !='\r')
&& (*cp != '\t') && (*cp != ' ')) return;
*cp = 0;
}
}
#if 0 /* never used */
int
timeval_clear(struct timeval *tv)
{
if (tv == NULL)
return -1;
tv->tv_sec = 0;
tv->tv_usec = 0;
return 0;
}
/* timetextbuf should be (SIZEOF_TIMEVALTEXT + 1) */
char *
timeval_to_text(const struct timeval *the_timeval, char *timetextbuf)
{
/*
* given a timeval (seconds and microseconds), put the text
* "seconds.microseconds" into timeval_as_text
*/
int seconds, microseconds;
seconds = the_timeval->tv_sec;
microseconds = the_timeval->tv_usec;
sprintf(timetextbuf, "%10d.%6.6d\t", seconds, microseconds);
return timetextbuf;
}
/* doubletextbuf should be (SIZEOF_DOUBLETEXT+1) */
char *
double_to_text(const double the_double, char *doubletextbuf)
{
/*
* given a double, return text
*/
sprintf(doubletextbuf, "%17.01f\t", the_double);
return(doubletextbuf);
}
struct timeval
text_to_timeval(ptcx_t ptcx, char *timeval_as_text) {
long int seconds, microseconds;
struct timeval the_timeval;
D_PRINTF(debugfile,"T/%d %s\n", (int)timeval_as_text, timeval_as_text);
sscanf(timeval_as_text, "%ld.%ld", &seconds, &microseconds);
the_timeval.tv_sec = seconds;
the_timeval.tv_usec = microseconds;
return the_timeval;
}
double
text_to_double(ptcx_t ptcx, char *double_as_text) {
double the_double = 0;
int returnval = 0;
D_PRINTF(debugfile,"D/%d %s\n", (int)double_as_text, double_as_text);
returnval = sscanf(double_as_text, "%lf", &the_double);
if (returnval == 1)
return(the_double);
else
return(0.0);
}
#endif
#if 0
/* not currently used, but useful for debugging */
void
dumpevent(ptcx_t ptcx, event_timer_t *pevent)
{
D_PRINTF(debugfile, "trys=%d errs=%d br=%f bw=%f elapsed=%f sq=%f\n",
pevent->trys, pevent->errs,
pevent->bytesread, pevent->byteswritten,
pevent->elapsedtime,
pevent->elapsedtimesq);
}
void
dumptimer(ptcx_t ptcx, cmd_stats_t *rqsttimer)
{
if (gn_debug) {
D_PRINTF(debugfile, "Connect: ");
dumpevent(ptcx, &rqsttimer->connect);
D_PRINTF(debugfile, "Banner: ");
dumpevent(ptcx, &rqsttimer->banner);
D_PRINTF(debugfile, "Login: ");
dumpevent(ptcx, &rqsttimer->login);
D_PRINTF(debugfile, "Cmd: ");
dumpevent(ptcx, &rqsttimer->cmd);
D_PRINTF(debugfile, "MsgRead: ");
dumpevent(ptcx, &rqsttimer->msgread);
D_PRINTF(debugfile, "MsgWrite: ");
dumpevent(ptcx, &rqsttimer->msgwrite);
D_PRINTF(debugfile, "Idle: ");
dumpevent(ptcx, &rqsttimer->idle);
D_PRINTF(debugfile, "Logout: ");
dumpevent(ptcx, &rqsttimer->logout);
}
}
#endif

514
mstone/src/bench.h Normal file
Просмотреть файл

@ -0,0 +1,514 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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): Dan Christian <robodan@netscape.com>
* Marcel DePaolis <marcel@netcape.com>
* Mike Blakely
* David Shak
*
* 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 __BENCH_H__
#define __BENCH_H__
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#include <float.h>
#include <sys/stat.h>
#include <assert.h>
#ifdef _WIN32
#include <windows.h>
#include <winsock.h>
#include <time.h>
#include <process.h>
#include <io.h>
#define NT_STACKSIZE 50*1024
#endif /* _WIN32 */
#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>
#include <math.h>
#include <sys/types.h>
#include <ctype.h>
#include <fcntl.h>
#ifndef _WIN32
#include <sys/poll.h>
#include <sys/param.h>
#include <sys/ipc.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/resource.h> /* for struct rlimit, RLIMIT_NOFILE */
#ifdef HAVE_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_WAIT_H
#include <wait.h>
#endif
#endif /* _WIN32 */
#include "sysdep.h"
#define USECINSEC 1000000
#define MSECINSEC 1000
#define MAX_ACCEPT_SECS 180 /* maximum time master will wait for listen() */
#define SECS_2_USECS(x) ((x) * USECINSEC)
#define USECS_2_SECS(x) ((x) / USECINSEC)
#define LINE_BUFSIZE 4096
#define MAXPROCSPERNODE 4096 /* max # of procs/node */
#define SMTP_PORT 25 /* standard port numbers */
#define POP3_PORT 110
#define IMAP4_PORT 143
#define HTTP_PORT 80
#define WMAP_PORT 80
#define CRLF "\r\n"
#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 */
/* levels for timeexpired */
#define EXIT_SOON 1 /* do a clean shutdown ASAP */
#define EXIT_FAST 20 /* shutdown now, dont block */
#define EXIT_FASTEST 50 /* close sockets unconnditionally */
/* Debug macros */
#define D_PRINTF if (gn_debug > 0) d_printf
#define T_PRINTF if (gn_record_telemetry) t_printf
/*
Simple keyword indexed string storage
This kind of thing has been invented many times. Once more with gusto!
*/
typedef struct param_list {
struct param_list *next;
char * name;
char * value;
} param_list_t;
/*
Simple keyword indexed string storage
This kind of thing has been invented many times. Once more with gusto!
*/
typedef struct string_list {
struct string_list *next;
char * value;
} string_list_t;
/* Numeric range (Shared). Previous value must be stored seperately */
typedef struct range {
unsigned long first; /* first valid value */
unsigned long last; /* last valid value */
unsigned long span; /* last-first */
int sequential; /* 0=random, +=sequential up, -=down */
} range_t;
/* basic timing structure */
typedef struct event_timer {
unsigned long trys;
unsigned long errs;
double bytesread;
double byteswritten;
double elapsedtime;
double elapsedtimesq;
double maxtime;
double mintime;
} event_timer_t;
/* command stats kept for every block and for every thread */
typedef struct cmd_stats {
/* This is protocol independent */
unsigned long totalerrs;
unsigned long totalcommands;
event_timer_t combined; /* AKA total */
event_timer_t idle;
void * data; /* protocol dependent data */
} cmd_stats_t;
typedef struct stats { /* used for throttling ??? */
struct timeval starttime;
struct timeval endtime;
unsigned int total_num_of_commands;
} stats_t;
typedef struct resolved_addr {
int resolved;
struct hostent host_phe;
struct protoent host_ppe;
unsigned long host_addr;
short host_type;
} resolved_addr_t;
typedef struct thread_context *ptcx_t;
typedef struct mail_command *pmail_command_t;
typedef struct protocol *p_protocol_t;
typedef int (*parseStartPtr_t)(pmail_command_t, char *, param_list_t *);
typedef int (*parseEndPtr_t)(pmail_command_t, string_list_t *, param_list_t *);
typedef void *(*commStartPtr_t)(ptcx_t , pmail_command_t , cmd_stats_t *);
typedef int (*commLoopPtr_t)(ptcx_t , pmail_command_t , cmd_stats_t *, void *);
typedef void (*commEndPtr_t)(ptcx_t , pmail_command_t , cmd_stats_t *, void *);
typedef void (*statsFormatPtr_t)(p_protocol_t, const char *extra, char *buf);
typedef void (*statsInitPtr_t)(pmail_command_t, cmd_stats_t *, int, int);
typedef void (*statsUpdatePtr_t)(p_protocol_t, cmd_stats_t *, cmd_stats_t *);
typedef void (*statsOutputPtr_t)(p_protocol_t, cmd_stats_t *, char *);
typedef struct protocol {
const char * name; /* text name */
parseStartPtr_t parseStart; /* section start parse routine */
parseEndPtr_t parseEnd; /* section end parse routine */
commStartPtr_t cmdStart; /* command start routine */
commLoopPtr_t cmdLoop; /* command loop routine */
commEndPtr_t cmdEnd; /* command end routine */
statsFormatPtr_t statsFormat; /* output format information */
statsInitPtr_t statsInit; /* init and zero stats structure */
statsUpdatePtr_t statsUpdate; /* sum commands */
statsOutputPtr_t statsOutput; /* output stats */
int cmdCount; /* commands using this protocol */
cmd_stats_t stats; /* total stats for this protocol */
} protocol_t;
/* This structure defines a mail command */
typedef struct mail_command {
/* Required fields */
protocol_t * proto;
int weight;
/* 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) */
void *data; /* protocol specific data */
} mail_command_t;
typedef struct child_context { /* forked sub processes */
int pid;
SOCKET socket;
} ccx_t, *pccx_t;
typedef struct thread_context {
/* initialized by parent thread */
THREAD_ID tid; /* thread id */
int processnum; /* ordinal process number */
int threadnum; /* ordinal thread number */
int random_seed; /* seed for srandom */
/* 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) */
struct timeval starttime; /* a starting timestamp */
int bytesread; /* num bytes read in per event */
int byteswritten; /* num bytes written per event */
int ofd; /* connection to master */
FILE *dfile; /* debug file */
int logfile; /* telemetry log file */
SOCKET sock; /* network connection */
char errMsg[MAX_ERRORMSG_LEN]; /* low level error string */
} tcx_t;
/* About errMsg:
This should store what was being attempted when a IO error occurs.
From errMsg and errno (or its NT equivalent) you should be able
to understand what went wrong.
No message is printed by the common functions (since some errors are
recoverable).
The protocol handlers combine errMsg with neterrstr() to generate
the message that the user sees (if not handled by the protocol).
Note that this is a small buffer (since it is replicated with every
thread). Don't try to stuff the read/written data into it.
The routine getting the system error sets errMsg (strcpy, or sprintf).
Calling routines append a "call trace" with additional info (strcat).
The "call trace" starts with '<' as a seperator.
*/
#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);
extern void event_reset(event_timer_t *pevent);
extern void event_sum(event_timer_t *psum, event_timer_t *pincr);
extern char *event_to_text(event_timer_t *pevent, char *ebuf);
extern void stats_init(stats_t *);
extern char * double_to_text(const double the_double, char *textbuf);
#if 0
extern cmd_stats_t *text_to_cmd_stats(ptcx_t ptcx, char *cmd_stats_as_text, cmd_stats_t *the_cmd_stats);
extern cmd_stats_t * text_to_cmd_stats(ptcx_t ptcx, char *, cmd_stats_t *the_cmd_stats);
extern stats_t * text_to_stats(ptcx_t ptcx, char *, stats_t *the_stats);
extern char * stats_to_text(ptcx_t ptcx, const stats_t *, char *statstextbuf);
#endif
/* shared variables */
extern int gn_debug;
extern int gn_record_telemetry;
extern int gn_total_weight;
extern int gn_client_throttle;
extern int gn_maxerrorcnt;
extern int gn_maxBlockCnt;
extern int gn_numprocs;
extern int gn_numthreads;
extern int gn_feedback_secs;
extern time_t gt_testtime;
extern time_t gt_startedtime;
extern volatile time_t gt_shutdowntime;
extern volatile int gf_timeexpired;
extern time_t gt_stopinterval; /* MAX (ramptime/5, 10) */
extern time_t gt_aborttime; /* startedtime + testtime + ramptime*/
extern int gn_number_of_commands;
extern int gf_abortive_close;
extern int gf_imapForceUniqueness;
extern char gs_dateStamp[DATESTAMP_LEN];
extern char gs_thishostname[];
extern char *gs_parsename;
extern pid_t gn_myPID;
extern mail_command_t *g_loaded_comm_list; /* actually a dynamic array */
extern protocol_t g_protocols[];
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 retryRead(ptcx_t ptcx, SOCKET sock, char *buf, int count);
extern int retryWrite(ptcx_t ptcx, SOCKET sock, char *buf, int count);
extern int recvdata(ptcx_t ptcx, SOCKET sock, char *ptr, int nbytes);
extern int senddata(ptcx_t ptcx, SOCKET sock, char *ptr, int nbytes);
extern void rqstat_times(cmd_stats_t *rs, cmd_stats_t *rt);
extern void rqstat_to_buffer(char *buf, char *comm, cmd_stats_t *stats);
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 sendMessage(ptcx_t ptcx, SOCKET sock, char *message);
extern int sendOutput(int fd, char *command);
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 );
void rangeSetFirstCount (range_t *, unsigned long , unsigned long , int );
void rangeSplit (range_t *whole, range_t *sub, int pnum, int tnum);
extern void cmdStatsInit (cmd_stats_t *p);
/* routines in sysdep.c */
extern void MS_usleep(unsigned int microsecs);
extern void MS_sleep(unsigned int secs);
/* routines in errexit.c */
extern void errexit(FILE *dfile, const char *, ...);
extern int returnerr(FILE *dfile, const char *, ...);
extern int d_printf(FILE *dfile, const char *, ...);
extern int t_printf(int fd, const char *buffer, size_t count, const char *format, ...);
extern char *neterrstr(void);
/* routines in smtp.c */
/* TRANSITION functions */
extern void pishStatsFormat (protocol_t *pp, const char *extra, char *buf);
extern void pishStatsInit(pmail_command_t, cmd_stats_t *, int pN, int tN);
extern void pishStatsUpdate(protocol_t *, cmd_stats_t *, cmd_stats_t *);
extern void pishStatsOutput(protocol_t *, cmd_stats_t *, char *);
extern int SmtpParseStart (pmail_command_t , char *, param_list_t *);
extern int SmtpParseEnd (pmail_command_t , string_list_t *, param_list_t *);
extern void *sendSMTPStart(ptcx_t ptcx, pmail_command_t, cmd_stats_t *);
extern int sendSMTPLoop(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
extern void sendSMTPEnd(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
/* routines in pop3.c */
extern int Pop3ParseStart (pmail_command_t , char *, param_list_t *);
extern int Pop3ParseEnd (pmail_command_t , string_list_t *, param_list_t *);
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 *);
/* routines in imap4.c */
extern int Imap4ParseStart (pmail_command_t , char *, param_list_t *);
extern int Imap4ParseEnd (pmail_command_t , string_list_t *, param_list_t *);
extern void *doImap4Start(ptcx_t ptcx, pmail_command_t, cmd_stats_t *);
extern int doImap4Loop(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
extern void doImap4End(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
/* routines in http.c */
extern int HttpParseStart (pmail_command_t , char *, param_list_t *);
extern int HttpParseEnd (pmail_command_t , string_list_t *, param_list_t *);
extern void HttpStatsFormat (protocol_t *pp, const char *extra, char *buf);
extern void HttpStatsInit(pmail_command_t, cmd_stats_t *, int pN, int tN);
extern void HttpStatsUpdate(protocol_t *, cmd_stats_t *, cmd_stats_t *);
extern void HttpStatsOutput(protocol_t *, cmd_stats_t *, char *);
extern void *doHttpStart(ptcx_t ptcx, pmail_command_t, cmd_stats_t *);
extern int doHttpLoop(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
extern void doHttpEnd(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
/* routines in wmap.c */
extern int WmapParseStart (pmail_command_t , char *, param_list_t *);
extern int WmapParseEnd (pmail_command_t , string_list_t *, param_list_t *);
extern void WmapStatsFormat (protocol_t *pp, const char *extra, char *buf);
extern void WmapStatsInit(pmail_command_t, cmd_stats_t *, int pN, int tN);
extern void WmapStatsUpdate(protocol_t *, cmd_stats_t *, cmd_stats_t *);
extern void WmapStatsOutput(protocol_t *, cmd_stats_t *, char *);
extern void *doWmapStart(ptcx_t ptcx, pmail_command_t, cmd_stats_t *);
extern int doWmapLoop(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
extern void doWmapEnd(ptcx_t ptcx, pmail_command_t, cmd_stats_t *, void *);
/* routines in parse.c */
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 load_commands(char *commands);
extern param_list_t *paramListInit (void);
/* paramListAdd returns: 1 update existing value, 0 new, -1 out of memory */
extern int paramListAdd (param_list_t *list, const char *name, const char *value);
/* paramListGet returns value or NULL */
extern char *paramListGet (param_list_t *list, const char *name);
extern param_list_t *g_default_params; /* default section params */
extern string_list_t *stringListInit (const char *value);
extern int stringListAdd (string_list_t *list, const char *value);
extern void stringListFree (string_list_t *list);
/* routines in timefunc.c */
extern double timevaldouble(struct timeval *);
extern void doubletimeval(const double, struct timeval *);
extern double compdifftime_double(struct timeval *End, struct timeval *Strt);
/* routines in main.c */
extern char *safe_inet_ntoa(struct in_addr ina, char *psz);
extern SOCKET connectsock(ptcx_t ptcx, char *host, resolved_addr_t *, NETPORT portnum,
char *protocol);
extern int set_abortive_close(SOCKET sock);
extern void throttle(ptcx_t ptcx, mail_command_t *comm, cmd_stats_t *timer);
/* routines in client.c */
extern void beginShutdown (void);
extern int clientInit(ptcx_t ptcx);
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 void MS_idle(ptcx_t ptcx, int idleSecs);
extern int resolve_addrs(char *host, char *protocol, struct hostent *host_phe,
struct protoent *proto_ppe, unsigned long *addr,
short *type);
#if 0
extern void dumpevent(ptcx_t ptcx, event_timer_t *pevent);
extern void dumptimer(ptcx_t ptcx, cmd_stats_t *rqsttimer);
extern int clientStats(ptcx_t ptcx);
unsigned long get_next_login(ptcx_t ptcx, mail_command_t *comm, cmd_stats_t *ptimer);
unsigned long get_next_address(ptcx_t ptcx, mail_command_t *comm, cmd_stats_t *ptimer);
#endif
#undef VERSION
#define VERSION "4.2"
#ifdef _DEBUG
#define MAILCLIENT_VERSION "mailclient (" VERSION " DEBUG built " __DATE__ " " __TIME__ ")"
#else
#define MAILCLIENT_VERSION "mailclient (" VERSION " built " __DATE__ " " __TIME__ ")"
#endif
FILE *fdopen(int fildes, const char *mode);
#ifndef _WIN32
extern int getopt(int, char *const *, const char *);
#endif
#ifndef __OSF1__
#ifndef __LINUX__
extern long random(void);
#endif
extern void srandom(unsigned);
#endif
#endif /* !__BENCH_H__ */

908
mstone/src/client.c Normal file
Просмотреть файл

@ -0,0 +1,908 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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 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.
*/
/*
client.c handles thread creation
login, loop, logout
status report generation
throttling (not supported yet)
thread joining
*/
#include "bench.h"
static int StartedThreads = 0; /* counter semaphore for children */
static int FinishedThreads = 0; /* counter semaphore for children */
#ifdef _WIN32
#define DEBUG_FILE "mstone-debug"
#define LOG_FILE "mstone-log"
#else
#define DEBUG_FILE "mstone-debug"
#define LOG_FILE "mstone-log"
#endif /* _WIN32 */
/*
This is a sleep that knows about test end.
Should also do throttling.
We dont check for signals because the only signal expected is test end
*/
void
MS_idle(ptcx_t ptcx, int idleSecs)
{
int secsLeft = 0;
secsLeft = gt_shutdowntime - time(0L);
D_PRINTF(debugfile, "secsLeft=%d, idleSecs=%d\n", secsLeft, idleSecs);
if (secsLeft <= 0) { /* time is up, start exiting */
if (gf_timeexpired < EXIT_SOON)
gf_timeexpired = EXIT_SOON;
return;
}
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;
/* we probably have not reached NETCLOSE yet, so we do not
know what timer->exittime is */
timeval_stamp(&exittime);
/* time to sleep = throttle - (exittime - entertime) */
chokeSecs = comm->throttle - ( exittime.tv_sec - ptcx->starttime.tv_sec );
/* 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
*
* commNum = the number of the comm (offset in loaded_comm_list[])
*
* returns 1
*/
static int
do_command(ptcx_t ptcx, /* thread state */
int commNum) /* command block number */
{
mail_command_t *comm = &g_loaded_comm_list[commNum];
cmd_stats_t *cmd_stats = &(ptcx->cmd_stats[commNum]);
int cnt, cntEnd; /* loop counters */
void *state = NULL;
cntEnd = comm->numLoops+1; /* transfer count +1 */
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++) {
if (gf_timeexpired >= EXIT_FAST) /* no more calls */
break;
if (gf_timeexpired >= EXIT_SOON) {
if (!state) break; /* no shutdown to do */
cnt = cntEnd; /* go to shutdown */
}
D_PRINTF(debugfile, "do_command t=%lu count=%d of %d\n",
time(0L), cnt, cntEnd);
if (0 == cnt) { /* first time */
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;
}
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;
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 */
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);
}
}
}
/* do blockTime even if we hit an error connecting */
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);
return 1; /* return connections */
} /* END do_command() */
/*
Initialize sub process context
*/
int
clientInit(ptcx_t ptcx)
{
ptcx->dfile = stderr;
if (gn_debug) {
/* open a debug log file */
char debug_file_name[255];
fflush(stderr);
if (ptcx->threadnum >= 0) {
sprintf(debug_file_name, "%s.%d.%d",
DEBUG_FILE, ptcx->processnum, ptcx->threadnum);
} else {
sprintf(debug_file_name, "%s.%d",
DEBUG_FILE, ptcx->processnum);
}
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");
}
D_PRINTF(debugfile, "Running in debug mode\n");
}
if (gn_record_telemetry) {
/* open a transaction log file. */
char log_file_name[255];
sprintf(log_file_name, "%s.%d.%d",
LOG_FILE, ptcx->processnum, ptcx->threadnum);
ptcx->logfile = open(log_file_name,
O_CREAT | O_TRUNC | O_WRONLY, 0664);
returnerr(debugfile,"Log file is %s [%d]\n", log_file_name, ptcx->logfile);
} else {
ptcx->logfile = -1;
}
/* Initialize random number generator */
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;
}
/* Continuously handle command blocks until time is up
*/
int
clientLoop(ptcx_t ptcx)
{
for(ptcx->blockCount = 0; gf_timeexpired < EXIT_SOON; ) {
int comm_index = 0;
if (gn_number_of_commands > 1) {
int ran_number;
/* Handle the weighted distribution of commands */
/* HAVE FILELIST */
D_PRINTF(debugfile, "Total weight %d\n", gn_total_weight);
/* random number between 0 and totalweight-1 */
ran_number = (RANDOM() % gn_total_weight);
D_PRINTF(debugfile, "random %ld\n", ran_number );
/* 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++;
D_PRINTF(debugfile, "Current command index %d: %ld - %d\n",
comm_index, ran_number,
g_loaded_comm_list[comm_index].weight
);
ran_number -= g_loaded_comm_list[comm_index].weight;
}
if (comm_index >= gn_number_of_commands) { /* shouldnt happen */
D_PRINTF(debugfile, "Command weight overrun %d %d\n",
ran_number, gn_total_weight);
comm_index--;
}
/*D_PRINTF(debugfile, "Final page index %d\n", comm_index );*/
}
/* run the command */
ptcx->connectCount += do_command(ptcx, comm_index);
++ptcx->blockCount;
if (gf_timeexpired >= EXIT_SOON) break; /* done, dont throttle */
/* For the single processes/thread case, this should be exact */
if ((gn_maxBlockCnt) /* check for max loops */
&& (ptcx->blockCount >= gn_maxBlockCnt)) {
D_PRINTF (debugfile, "Saw enough loops %d, exiting\n",
ptcx->blockCount);
beginShutdown (); /* indicate early exit */
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;
}
/*
Thread of execution.
Also works in un-threaded case.
Initialize, do some system housekeeping, run test, housekeeping, clean up
*/
THREAD_RET
clientThread(void *targ)
{
time_t currentTime;
struct tm *tmptm;
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
if (ptcx->threadnum >= 0)
pthread_exit((void *)((1 << 16) | ptcx->threadnum));
return NULL;
#else
return;
#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(&currentTime);
tmptm = localtime(&currentTime);
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);
}
#ifdef _WIN32
#define WAIT_INFINITY 100000000
/* Tell parent we're ready */
InterlockedIncrement(&StartedThreads);
#else
++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 */
time(&currentTime);
tmptm = localtime(&currentTime);
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;
}
}
/*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??? */
#ifdef USE_PTHREADS
if (ptcx->threadnum >= 0)
pthread_exit((void *)((ret << 16) | ptcx->threadnum));
#endif
return NULL;
#endif /* _WIN32 */
} /* END clientThread() */
/*
The FORMAT format is:
FORMAT: client=<NUMBER> <TYPE>:<NAME>\t<VALUE>
TYPE is one of: TIMER, PROTOCOL, LINE
Everything breaks down to attribute=value pairs.
"attribute=" is literal, the listed value names the field
Attribute names must be unique with each timer.
The [] and {} indicate timers and protocols respectively.
everything else is a literal (including whitespace).
The protocols and timers will be expanded with simple text
substitutions.
The literal text is as high in the description as possible.
The processing splits out the values based on surrounding text.
*/
/*
Output the format that the summaries will be in.
This call the protocol specific formats, then outputs
the complete line formats
*/
void
clientSummaryFormat(int clientnum, int outfd)
{
char buf[SIZEOF_SUMMARYTEXT], *cp;
char extra[96];
protocol_t *pp;
sprintf (extra, "client=%d", clientnum); /* extra stuff on each line */
/* Define the contents of each protocol */
for (pp=g_protocols; pp->name != NULL; ++pp) {
if (!pp->cmdCount) continue; /* not used */
(pp->statsInit)(NULL, &(pp->stats), 0, 0); /* init stats (HERE?) */
(pp->statsFormat)(pp, extra, buf); /* output lines of format info */
sendOutput(outfd, buf);
}
/* Define the periodic update summaries */
/* This is the most common message, so keep is as short as practical */
cp = buf;
sprintf(cp,
"<FORMAT %s LINE=SUMMARY-TIME><TS %s>",
extra,
"client=client t=time blocks=blocks");
for (; *cp; ++cp); /* skip to the end of the string */
for (pp=g_protocols; pp->name != NULL; ++pp) {
if (!pp->cmdCount) continue; /* not used */
sprintf(cp, "\t<%s {%s}/>", pp->name, pp->name);
for (; *cp; ++cp); /* skip to the end of the string */
}
strcat (cp, "</TS></FORMAT>\n");
sendOutput(outfd, buf);
/* BLOCK-STATISTICS format */
for (pp=g_protocols; pp->name != NULL; ++pp) {
cp = buf;
sprintf(cp,
"<FORMAT %s LINE=BLOCK-STATISTICS-%s><BS-%s %s>",
extra, pp->name, pp->name,
"client=client thread=thread t=time blockID=blockID");
for (; *cp; ++cp); /* skip to the end of the string */
sprintf(cp, "\t<%s {%s}/>", pp->name, pp->name);
for (; *cp; ++cp); /* skip to the end of the string */
sprintf (cp, "</BS-%s></FORMAT>\n", pp->name);
sendOutput(outfd, buf);
}
/* Notice Format */
sprintf(buf,
"<FORMAT %s LINE=NOTICE-1>%s</FORMAT>\n",
extra,
"<NOTICE client=client ... ");
sendOutput(outfd, buf);
/* Abort Format */
sprintf(buf,
"<FORMAT %s LINE=NOTICE-2>%s</FORMAT>\n",
extra,
"<ABORT client=client ... ");
sendOutput(outfd, buf);
}
/*
Output the block information for each thread
*/
void
clientBlockSummary(ptcx_t ptcxs, int ntcxs, int clientnum, int outfd)
{
time_t curtime;
protocol_t *pp;
int jj, kk;
char buf[SIZEOF_SUMMARYTEXT], *bp;
D_PRINTF(stderr, "clientSummaryBS starting.\n" );
curtime = time(0L);
for (kk = 0; kk < gn_number_of_commands; ++kk) { /* all commands */
for (jj = 0; jj < ntcxs; ++jj) { /* all threads */
if (0 == ptcxs[jj].cmd_stats[kk].totalcommands) /* nothing */
continue;
pp = g_loaded_comm_list[kk].proto;
/* output proto independent part */
bp = buf;
sprintf (bp,
"<BS-%s client=%d thread=%d t=%lu blockID=%d>",
pp->name, clientnum, jj, curtime,
g_loaded_comm_list[kk].blockID);
for (; *bp; ++bp); /* find end of buffer */
sprintf (bp,
"\t<%s blocks=%ld ",
pp->name,
ptcxs[jj].cmd_stats[kk].totalcommands);
for (; *bp; ++bp); /* find end of buffer */
(pp->statsOutput)(pp, &(ptcxs[jj].cmd_stats[kk]), bp);
for (; *bp; ++bp); /* find end of buffer */
sprintf (bp, "/></BS-%s>\n", pp->name); /* end it */
sendOutput(outfd, buf);
}
}
D_PRINTF(stderr, "clientSummaryBS done.\n");
}
/* Output the periodic activity summary */
void
clientTimeSummary(ptcx_t ptcxs, int ntcxs, int clientnum, int outfd)
{
time_t curtime;
int blockCount = 0, connectCount = 0;
protocol_t *pp;
int jj, kk;
char buf[SIZEOF_SUMMARYTEXT];
char rqsttextbuf[SIZEOF_RQSTSTATSTEXT+1];
static int oldThreadStarts= 0;
static int oldThreadEnds= 0;
D_PRINTF(stderr, "clientTimeSummary starting.\n" );
curtime = time(0L);
for (pp=g_protocols; pp->name != NULL; ++pp) { /* zero protocol stats */
if (!pp->cmdCount) continue; /* not used */
cmdStatsInit (&(pp->stats)); /* clear proto independent part */
(pp->statsInit)(NULL, &(pp->stats), 0, 0); /* clear proto part */
}
/* sum by protocol all commands, all threads */
for (jj = 0; jj < ntcxs; ++jj) {
blockCount += ptcxs[jj].blockCount;
connectCount += ptcxs[jj].connectCount;
for (kk = 0; kk < gn_number_of_commands; ++kk) {
pp = g_loaded_comm_list[kk].proto;
(pp->statsUpdate)(pp, &pp->stats, &(ptcxs[jj].cmd_stats[kk]));
}
}
/* output proto independent part */
sprintf(buf, "<TS client=%d t=%lu blocks=%d>",
clientnum, curtime, blockCount);
for (pp=g_protocols; pp->name != NULL; ++pp) { /* output proto parts */
if (!pp->cmdCount) continue; /* not used */
(pp->statsOutput)(pp, &pp->stats, rqsttextbuf);
/* The \t seperates sections for report parsing */
sprintf(&buf[strlen(buf)], "\t<%s blocks=%ld %s/>",
pp->name, pp->stats.totalcommands,
rqsttextbuf);
}
strcat(buf, "</TS>\n"); /* end it */
sendOutput(outfd, buf);
/* do additional status updates */
if (oldThreadStarts != StartedThreads) {
sprintf(buf, "<NOTICE client=%d threadStarts=%d/>\n",
clientnum, StartedThreads - oldThreadStarts);
sendOutput(outfd, buf);
oldThreadStarts = StartedThreads;
}
if (oldThreadEnds != FinishedThreads) {
sprintf(buf, "<NOTICE client=%d threadFinishes=%d/>\n",
clientnum, FinishedThreads - oldThreadEnds);
sendOutput(outfd, buf);
oldThreadEnds = FinishedThreads;
}
if (gn_maxerrorcnt) { /* check for max error count */
int errors = 0;
for (pp=g_protocols; pp->name != NULL; ++pp) { /* sum total */
if (!pp->cmdCount) continue; /* not used */
errors += pp->stats.combined.errs;
}
if (errors > gn_maxerrorcnt) {
returnerr (stderr,
"<ABORT client=%d errorCount=%ld errorLimit=%ld/>\n",
clientnum, errors, gn_maxerrorcnt);
beginShutdown ();
}
}
if ((gn_maxBlockCnt)
&& (blockCount >= gn_maxBlockCnt)) { /* check for max loops */
returnerr (stderr,
"<ABORT client=%d blockCount=%ld blockLimit=%ld/>\n",
clientnum, blockCount, gn_maxBlockCnt);
beginShutdown ();
}
D_PRINTF(stderr, "clientTimeSummary done.\n");
}
/*
Thread that calls clientTimeSummary at the right rate
*/
THREAD_RET
summaryThread(void *targ)
{
ptcx_t ptcxs = (ptcx_t)targ; /* thread contexts */
D_PRINTF(stderr, "summaryThread starting...\n");
/* client threads running...dump periodic stats */
while (gn_feedback_secs && (gf_timeexpired < EXIT_FAST)) {
D_PRINTF(stderr, "client %d: clientTimeSummary\n", ptcxs[0].processnum);
clientTimeSummary(ptcxs, gn_numthreads, ptcxs[0].processnum, ptcxs[0].ofd);
D_PRINTF(stderr, "client %d: waiting %d seconds before feedback\n",
ptcxs[0].processnum, gn_feedback_secs);
MS_sleep(gn_feedback_secs);
}
D_PRINTF(stderr, "summaryThread exiting...\n");
#ifdef USE_PTHREADS
pthread_exit(0);
#endif
#ifndef _WIN32
return NULL;
#endif
}
/*
Initialize per thread context
*/
void
initTcx(ptcx_t ptcx, int ofd, int pnum, int tnum)
{
int kk;
ptcx->processnum = pnum;
ptcx->threadnum = tnum;
ptcx->random_seed = (tnum << 16) + getpid();
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) {
(g_loaded_comm_list[kk].proto->statsInit)
(&g_loaded_comm_list[kk], &(ptcx->cmd_stats[kk]), pnum, tnum);
}
ptcx->ofd = ofd;
ptcx->sock = BADSOCKET_VALUE;
}
void
destroyTcx(ptcx_t ptcx)
{
if (ptcx->cmd_stats) {
free(ptcx->cmd_stats);
ptcx->cmd_stats = 0;
}
}
static time_t bailtime;
/* advance directly to shutdown phase. May be called from signal handlers */
void
beginShutdown (void)
{
if (gf_timeexpired >= EXIT_SOON) return; /* already shutting down */
gf_timeexpired = EXIT_SOON;
gt_shutdowntime = bailtime = time(0); /* advance end time to now */
/* Changing aborttime probably has no effect (wrong process) */
gt_aborttime = gt_shutdowntime + gt_stopinterval*2*EXIT_FASTEST;
}
/* This is the guts of each sub process.
The socket for data output has already be setup.
init context
start threads (if possible/needed) with proper rampup delays
wait for threads to end
*/
int
clientProc(int pnum, SOCKET 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, "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 ();
#ifndef _WIN32
alarm(testtime); /* promptly notice test end */
#endif
clientSummaryFormat (pnum, outfd);
#if defined(USE_PTHREADS) || defined(_WIN32)
if (gn_numthreads > 0) {
ptcxs = (ptcx_t)mycalloc(sizeof(tcx_t) * gn_numthreads);
for (tnum = 0; tnum < gn_numthreads; ++tnum) {
initTcx(&ptcxs[tnum], outfd, pnum, tnum);
}
/*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)
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: thread %d testtime %d\n",
pnum, tnum, testtime);
if ((ret=sysdep_thread_create(&(ptcxs[tnum].tid), clientThread,
(void *)&ptcxs[tnum])) != 0) {
returnerr(stderr, "client %d: thread %d create() failed ret=%d errno=%d: %s\n",
pnum, tnum, ret, errno, strerror(errno));
ptcxs[tnum].tid = 0;
}
D_PRINTF(stderr, "client %d: thread %d created with ID %d\n",
pnum, tnum, ptcxs[tnum].tid);
}
/* threads are going, but wait for them to get through setup */
while (StartedThreads < gn_numthreads) {
int tm = time(0);
if (tm > bailtime) {
++gf_timeexpired;
bailtime += gt_stopinterval;
}
if (gf_timeexpired >= EXIT_SOON) /* failsafe if thread count bad */
break;
MS_sleep(2);
}
D_PRINTF(stderr, "client %d: started all threads.\n", pnum);
/* Wait for all threads to exit or overtime */
while (FinishedThreads < StartedThreads) {
int tm = time(0);
if (tm > bailtime) {
++gf_timeexpired;
bailtime += gt_stopinterval;
#ifndef _WIN32
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 */
}
#endif
}
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));
}
#ifndef _WIN32
/* 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);
for (tnum = 0; tnum < gn_numthreads; ++tnum) {
D_PRINTF(stderr, "client %d: joining thread %d ID %d\n",
pnum, tnum, ptcxs[tnum].tid);
if (ptcxs[tnum].tid) {
sysdep_thread_join(ptcxs[tnum].tid, &status);
D_PRINTF(stderr, "client %d: thread %d joined ID %d, ret=%d status=%d\n",
pnum, tnum, ptcxs[tnum].tid, ret, status);
ptcxs[tnum].tid = 0;
}
}
#endif /* _WIN32 */
} else
#endif /* USE_PTHREADS || _WIN32*/
{ /* thread un-available or 0 */
gn_numthreads = 1;
ptcxs = (ptcx_t)mycalloc(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);
#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]);
}
#endif
for (tnum = 0; tnum < gn_numthreads; ++tnum) { /* clean up */
D_PRINTF(stderr, "client %d: thread %d destroyed\n", pnum, tnum);
destroyTcx(&ptcxs[tnum]);
}
D_PRINTF(stderr, "child: %d done\n", pnum);
return 0;
}

201
mstone/src/errexit.c Normal file
Просмотреть файл

@ -0,0 +1,201 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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): Dan Christian <robodan@netscape.com>
* Marcel DePaolis <marcel@netcape.com>
* Mike Blakely
*
* 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.
*/
/* calls for general error handling */
#include "bench.h"
#ifdef HAVE_VPRINTF
#define VPRINTF(stderr, format, args) vfprintf((stderr), (format), (args))
#else
#ifdef HAVE_DOPRNT
#define VPRINTF(stderr, format, args) _doprnt((format), (args), (stderr))
#endif /* HAVE_DOPRNT */
#endif /* HAVE_VPRINTF */
/* print an error message and exit 1 */
void
errexit(FILE *dfile, const char *format, ...)
{
time_t t=time(0L) - gt_startedtime;
va_list args;
#if defined (HAVE_SNPRINTF) && defined (HAVE_VPRINTF)
char buff[1024];
int r;
#endif
va_start(args, format);
#if defined (HAVE_SNPRINTF) && defined (HAVE_VPRINTF)
/* puts as one chunk so that output doesnt get mixed up */
r = snprintf(buff, sizeof(buff),
"%s[%d]\tt=%lu EXITING: ", gs_thishostname, gn_myPID, t);
vsnprintf(buff+r, sizeof(buff) - r, format, args);
fputs (buff, stderr);
fflush(stderr);
if (gn_debug && dfile && (dfile != stderr)) {
fputs (buff, dfile);
fflush(dfile);
}
#else
fprintf(stderr,
"%s[%d]\tt=%lu EXITING: ", gs_thishostname, gn_myPID, t);
VPRINTF(stderr, format, args);
fflush(stderr);
if (gn_debug && dfile && (dfile != stderr)) {
fprintf(dfile,
"%s[%d]\tt=%lu EXITING: ", gs_thishostname, gn_myPID, t);
VPRINTF(dfile, format, args);
fflush(dfile);
}
#endif
va_end(args);
exit(1);
}
/* This is the main feedback path for errors and status */
/* print an error message and return -1 */
/* Also log to the debug file if available */
int
returnerr(FILE *dfile, const char *format, ...)
{
time_t t=time(0L) - gt_startedtime;
va_list args;
#if defined (HAVE_SNPRINTF) && defined (HAVE_VPRINTF)
char buff[1024];
int r;
#endif
va_start(args, format);
#if defined (HAVE_SNPRINTF) && defined (HAVE_VPRINTF)
/* puts as one chunk so that output doesnt get mixed up */
r = snprintf(buff, sizeof(buff),
"%s[%d]\tt=%lu: ", gs_thishostname, gn_myPID, t);
vsnprintf(buff+r, sizeof(buff) - r, format, args);
fputs (buff, stderr);
fflush(stderr);
if (gn_debug && dfile && (dfile != stderr)) {
fputs (buff, dfile);
fflush(dfile);
}
#else
fprintf(stderr,
"%s[%d]\tt=%lu: ", gs_thishostname, gn_myPID, t);
VPRINTF(stderr, format, args);
fflush(stderr);
if (gn_debug && dfile && (dfile != stderr)) {
fprintf(dfile,
"%s[%d]\tt=%lu: ", gs_thishostname, gn_myPID, t);
VPRINTF(dfile, format, args);
fflush(dfile);
}
#endif
va_end(args);
return(-1);
}
/* print a debug message and then flush */
int
d_printf(FILE *dfile, const char *format, ...)
{
va_list args;
va_start(args, format);
if (dfile) {
fprintf(dfile, "%s: ", gs_thishostname);
VPRINTF(dfile, format, args);
}
va_end(args);
if (dfile) fflush(dfile);
return 0;
}
/* that's it */
/*
Like d_printf, but for transaction logs.
*/
int
t_printf(int fd, const char *buffer, size_t count, const char *format, ...)
{
time_t t=time(0L) - gt_startedtime;
va_list args;
char buff[1024];
int r;
if (fd <= 0) return 0;
va_start(args, format);
#if defined (HAVE_SNPRINTF) && defined (HAVE_VPRINTF)
r = snprintf(buff, sizeof(buff), /* stick in standard info */
"<LOG t=%lu length=%d ", t, count);
snprintf(buff + r, sizeof(buff) - r, format, args);
strcat (buff, ">\n");
write (fd, buff, strlen(buff));
write (fd, buffer, count); /* write the (possibly binary) data */
r = snprintf(buff, sizeof(buff), /* terminate entry cleanly */
"\n</LOG t=%lu length=%d>\n", t, count);
write (fd, buff, strlen(buff));
#else
write (fd, buffer, count); /* write the (possibly binary) data */
#endif
va_end(args);
return 0;
}
/* that's it */
/* returns the last network error as a string */
char *
neterrstr(void) {
static char buf[200];
#ifdef _WIN32
sprintf(buf, "WSAGetLastError()=%d", WSAGetLastError());
WSASetLastError(0);
#else /* !_WIN32 */
sprintf(buf, "errno=%d: %s", errno, strerror(errno));
errno = 0;
#endif /* _WIN32 */
return buf;
}

492
mstone/src/http.c Normal file
Просмотреть файл

@ -0,0 +1,492 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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 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.
*/
/* http.c: HTTP protocol test */
#include "bench.h"
#include "pish.h"
#define MAX_HTTP_RESPONSE_LEN (2*1024) /* size of sliding buffer */
/*
these are protocol dependent timers for Pop, Imap, Smtp, Http
There is one of these for every command in every thread.
*/
typedef struct http_stats {
event_timer_t connect;
event_timer_t msgread; /* AKA retrieve */
event_timer_t logout; /* AKA dis-connect */
/* no local storage */
} http_stats_t;
/*
State during command execution.
*/
typedef struct _doHTTP_state {
int numMsgs; /* messages in folder */
int totalMsgLength; /* total msg length */
int msgCounter; /* count in download */
} doHTTP_state_t;
static void doHttpExit (ptcx_t ptcx, doHTTP_state_t *me);
static int readHttpResponse(ptcx_t ptcx, SOCKET sock, char *buffer, int buflen);
static int doHttpCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen);
/*
Set defaults in command structure
*/
int
HttpParseStart (pmail_command_t cmd,
char *line,
param_list_t *defparm)
{
param_list_t *pp;
pish_command_t *pish = (pish_command_t *)mycalloc
(sizeof (pish_command_t));
cmd->data = pish;
cmd->numLoops = 1; /* default 1 downloads */
pish->portNum = HTTP_PORT; /* get default port */
D_PRINTF(stderr, "Http Assign defaults\n");
/* Fill in defaults first, ignore defaults we dont use */
for (pp = defparm; pp; pp = pp->next) {
(void)pishParseNameValue (cmd, pp->name, pp->value);
}
return 1;
}
/*
Fill in structure from a list of lines
*/
int
HttpParseEnd (pmail_command_t cmd,
string_list_t *section,
param_list_t *defparm)
{
pish_command_t *pish = (pish_command_t *)cmd->data;
string_list_t *sp;
/* Now parse section lines */
D_PRINTF(stderr, "Http Assign section lines\n");
/* 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 (pishParseNameValue (cmd, name, tok) < 0) {
/* not a known attr */
D_PRINTF(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 (!pish->mailServer) {
D_PRINTF(stderr,"missing server for command");
return returnerr(stderr,"missing server for command\n");
}
if (!pish->httpCommand) {
D_PRINTF(stderr,"missing httpcommand for HTTP");
return returnerr(stderr,"missing httpcommand for HTTP\n");
}
/* see if we can resolve the mailserver addr */
if (resolve_addrs(pish->mailServer, "tcp",
&(pish->hostInfo.host_phe),
&(pish->hostInfo.host_ppe),
&(pish->hostInfo.host_addr),
&(pish->hostInfo.host_type))) {
return returnerr (stderr, "Error resolving hostname '%s'\n",
pish->mailServer);
} else {
pish->hostInfo.resolved = 1; /* mark the hostInfo resolved */
}
return 1;
}
/* PROTOCOL specific */
void
HttpStatsInit(mail_command_t *cmd, cmd_stats_t *p, int procNum, int threadNum)
{
assert (NULL != p);
if (!p->data) { /* create it */
p->data = mycalloc (sizeof (http_stats_t));
} else { /* zero it */
memset (p->data, 0, sizeof (http_stats_t));
}
if (cmd) { /* do sub-range calulations */
/*pish_command_t *pish = (pish_command_t *)cmd->data;
http_stats_t *stats = (http_stats_t *)p->data;*/
}
}
/* PROTOCOL specific */
void
HttpStatsUpdate(protocol_t *proto,
cmd_stats_t *sum,
cmd_stats_t *incr)
{
http_stats_t *ss = (http_stats_t *)sum->data;
http_stats_t *is = (http_stats_t *)incr->data;
event_sum(&sum->idle, &incr->idle);
event_sum(&ss->connect, &is->connect);
event_sum(&ss->msgread, &is->msgread);
event_sum(&ss->logout, &is->logout);
event_reset(&incr->combined); /* figure out total */
event_sum(&incr->combined, &incr->idle);
event_sum(&incr->combined, &is->connect);
event_sum(&incr->combined, &is->msgread);
event_sum(&incr->combined, &is->logout);
event_sum(&sum->combined, &incr->combined); /* add our total to sum-total*/
sum->totalerrs += incr->totalerrs;
sum->totalcommands += incr->totalcommands;
}
/* PROTOCOL specific */
void
HttpStatsOutput(protocol_t *proto,
cmd_stats_t *ptimer,
char *buf)
{
char eventtextbuf[SIZEOF_EVENTTEXT];
http_stats_t *stats = (http_stats_t *)ptimer->data;
*buf = 0;
/* BUG blocks done in clientSummary */
event_to_text(&ptimer->combined, eventtextbuf);
sprintf(&buf[strlen(buf)], "total=%s ", eventtextbuf);
event_to_text(&stats->connect, eventtextbuf);
sprintf(&buf[strlen(buf)], "conn=%s ", eventtextbuf);
event_to_text(&stats->msgread, eventtextbuf);
sprintf(&buf[strlen(buf)], "retrieve=%s ", eventtextbuf);
event_to_text(&stats->logout, eventtextbuf);
sprintf(&buf[strlen(buf)], "logout=%s ", eventtextbuf);
event_to_text(&ptimer->idle, eventtextbuf);
sprintf(&buf[strlen(buf)], "idle=%s ", eventtextbuf);
}
/* PROTOCOL specific */
void
HttpStatsFormat (protocol_t *pp,
const char *extra, /* extra text to insert (client=) */
char *buf)
{
static char *timerList[] = { /* must match order of StatsOutput */
"total",
"conn", "retrieve", "logout",
"idle" };
char **tp;
char *cp = buf;
int ii;
/* Define the contents of each timer
These must all the same, to that the core time functions
can be qualified. We specify each one for reduce.pl to work right.
*/
for (ii=0, tp=timerList;
ii < (sizeof (timerList)/sizeof (timerList[0]));
++ii, ++tp) {
sprintf(cp, "<FORMAT %s TIMER=[%s]>%s</FORMAT>\n",
extra, *tp,
gs_eventToTextFormat); /* match event_to_text*/
for (; *cp; ++cp); /* skip to the end of the string */
}
/* BUG blocks matches clientSummary */
sprintf(cp, "<FORMAT %s PROTOCOL={%s}>blocks=blocks ",
extra, pp->name);
for (; *cp; ++cp); /* skip to the end of the string */
for (ii=0, tp=timerList; /* same as above list (for now) */
ii < (sizeof (timerList)/sizeof (timerList[0]));
++ii, ++tp) {
sprintf (cp, "%s=[%s] ", *tp, *tp);
for (; *cp; ++cp); /* skip to the end of the string */
}
strcat (cp, "</FORMAT>\n");
}
static int
readHttpResponse(ptcx_t ptcx, SOCKET sock, char *buffer, int buflen)
{
/* read the server response and do nothing with it */
int totalbytesread = 0;
int bytesread;
memset (buffer, 0, buflen);
while (totalbytesread < buflen)
{
if (gf_timeexpired >= EXIT_FAST) {
D_PRINTF(debugfile,"readHttpResponse() Time expired.\n");
break;
}
bytesread = retryRead(ptcx, sock, buffer, buflen-1);
if (bytesread == 0) /* just read until we hit emtpy */
break;
if (bytesread < 0) { /* IO error */
strcat (ptcx->errMsg, "<ReadHttpResponse");
return -1;
}
totalbytesread += bytesread;
buffer[bytesread] = 0; /* terminate for later searches */
ptcx->bytesread += bytesread;
T_PRINTF(ptcx->logfile, buffer, bytesread, "HTTP ReadResponse");
}
D_PRINTF(debugfile, "Read %d from server [%.99s]\n", totalbytesread, buffer);
if (0 == totalbytesread) {
strcpy (ptcx->errMsg, "ReadHttpResponse: Read 0 bytes");
return -1;
}
return totalbytesread;
}
/* expects pointers to buffers of these sizes */
/* char command[MAX_COMMAND_LEN] */
/* char response[resplen] */
static int
doHttpCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen)
{
int ret;
if (response == NULL)
return -1;
memset(response, 0, resplen);
T_PRINTF(ptcx->logfile, command, strlen (command), "HTTP SendCommand");
/* send the command already formatted */
if ((ret = sendCommand(ptcx, sock, command)) == -1) {
if (gf_timeexpired < EXIT_FAST) {
returnerr(debugfile, "Error sending [%s] command to server: %s\n",
command, neterrstr());
}
return -1;
}
/* read server response */
if ((ret = readHttpResponse(ptcx, sock, response, resplen)) <= 0) {
if (gf_timeexpired < EXIT_FAST) {
trimEndWhite (command);
returnerr(debugfile, "Error reading [%s] response: %s\n",
command, neterrstr());
}
return -1;
}
return ret;
}
#if 0
int
httpLogin(ptcx_t ptcx, mail_command_t *cmd, SOCKET sock)
{
char command[MAX_COMMAND_LEN];
char respBuffer[MAX_RESPONSE_LEN];
char mailUser[MAX_MAILADDR_LEN];
char userPasswd[MAX_MAILADDR_LEN];
unsigned long loginNum;
/* generate a random username (with a mailbox on the server) */
loginNum = (RANDOM() % pish->numLogins);
/* add the the base user */
loginNum += pish->firstLogin;
sprintf(mailUser, pish->loginFormat, loginNum);
D_PRINTF(debugfile,"mailUser=%s\n", mailUser);
sprintf(command, "USER %s%s", mailUser, CRLF);
if (doHttpCommandResponse(ptcx, sock, command, respBuffer) == -1) {
return -1;
}
/* send Password */
sprintf(userPasswd, pish->passwdFormat, loginNum);
sprintf(command, "PASS %s%s", userPasswd, CRLF);
if (doHttpCommandResponse(ptcx, sock, command, respBuffer) == -1) {
if (gf_timeexpired < EXIT_FAST) {
returnerr(debugfile,"HTTP cannot login user=%s pass=%s\n",
mailUser, userPasswd);
}
return -1;
}
return 0;
}
#endif
void *
doHttpStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
{
doHTTP_state_t *me = (doHTTP_state_t *)mycalloc (sizeof (doHTTP_state_t));
http_stats_t *stats = (http_stats_t *)ptimer->data;
pish_command_t *pish = (pish_command_t *)cmd->data;
NETPORT port;
if (!me) return NULL;
me->numMsgs = 0;
me->totalMsgLength = 0;
me->msgCounter = 0;
port = pish->portNum;
event_start(ptcx, &stats->connect);
ptcx->sock = connectsock(ptcx, pish->mailServer, &pish->hostInfo, port, "tcp");
event_stop(ptcx, &stats->connect);
if (BADSOCKET(ptcx->sock)) {
if (gf_timeexpired < EXIT_FAST) {
stats->connect.errs++;
returnerr(debugfile,
"%s<wmapConnect: HTTP Couldn't connect to %s: %s\n",
ptcx->errMsg, pish->mailServer, neterrstr());
}
myfree (me);
return NULL;
}
if (gf_abortive_close) {
if (set_abortive_close(ptcx->sock) != 0) {
returnerr (debugfile,
"HTTP: WARNING: Could not set abortive close\n");
}
}
/* there is no banner or login state for HTTP */
return me;
}
int
doHttpLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
{
doHTTP_state_t *me = (doHTTP_state_t *)mystate;
char command[MAX_COMMAND_LEN];
char respBuffer[MAX_HTTP_RESPONSE_LEN];
int rc;
http_stats_t *stats = (http_stats_t *)ptimer->data;
pish_command_t *pish = (pish_command_t *)cmd->data;
#if 0
if (me->msgCounter >= me->numMsgs)
return -1; /* done, close */
#endif
/* send the HTTP command */
/* will have to deal with encoding URLs before too long... */
sprintf(command, pish->httpCommand, me->msgCounter);
strcat(command, " HTTP/1.0\r\n");
/* other headers go here... */
strcat(command, "\r\n");
event_start(ptcx, &stats->msgread);
rc = doHttpCommandResponse(ptcx, ptcx->sock,
command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->msgread);
if (rc == 0) {
doHttpExit (ptcx, me);
return -1;
}
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->msgread.errs++;
}
doHttpExit (ptcx, me);
return -1;
}
return 0;
}
void
doHttpEnd(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
{
doHTTP_state_t *me = (doHTTP_state_t *)mystate;
http_stats_t *stats = (http_stats_t *)ptimer->data;
if (BADSOCKET(ptcx->sock)) return; /* closed by previous error */
#if 0
int rc;
char command[MAX_COMMAND_LEN];
char respBuffer[MAX_RESPONSE_LEN];
/* send HTTP QUIT equivalent */
sprintf(command, "QUIT%s", CRLF);
event_start(ptcx, &stats->logout);
rc = doHttpCommandResponse(ptcx, ptcx->sock, command, respBuffer);
event_stop(ptcx, &stats->logout);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->logout.errs++;
}
}
#else
event_start(ptcx, &stats->logout);
NETCLOSE(ptcx->sock); ptcx->sock = BADSOCKET_VALUE;
event_stop(ptcx, &stats->logout);
#endif
doHttpExit (ptcx, me);
}
void
doHttpExit (ptcx_t ptcx, doHTTP_state_t *me)
{
if (!BADSOCKET(ptcx->sock))
NETCLOSE(ptcx->sock);
ptcx->sock = BADSOCKET_VALUE;
myfree (me);
}

1015
mstone/src/imap4.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

Просмотреть файл

976
mstone/src/main.c Normal file
Просмотреть файл

@ -0,0 +1,976 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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 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.
*/
/*
main.c handles all the initialization and then forks off sub processes.
*/
#include "bench.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*/
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;
int gn_numthreads = 0;
int gn_debug = 0;
int gn_feedback_secs = 5;
int gf_abortive_close = 0;
int gn_number_of_commands = 0;
int gf_imapForceUniqueness = 0;
char gs_dateStamp[DATESTAMP_LEN];
char gs_thishostname[MAXHOSTNAMELEN+10] = "";
char *gs_parsename = gs_thishostname; /* name used during parsing */
pid_t gn_myPID = 0;
mail_command_t *g_loaded_comm_list; /* actually a dynamic array */
protocol_t g_protocols[] = { /* array of protocol information */
{
"SMTP",
SmtpParseStart,
SmtpParseEnd,
sendSMTPStart,
sendSMTPLoop,
sendSMTPEnd,
pishStatsFormat,
pishStatsInit,
pishStatsUpdate,
pishStatsOutput,
},
{
"POP3",
Pop3ParseStart,
Pop3ParseEnd,
doPop3Start,
doPop3Loop,
doPop3End,
pishStatsFormat,
pishStatsInit,
pishStatsUpdate,
pishStatsOutput,
},
{
"IMAP4",
Imap4ParseStart,
Imap4ParseEnd,
doImap4Start,
doImap4Loop,
doImap4End,
pishStatsFormat,
pishStatsInit,
pishStatsUpdate,
pishStatsOutput,
},
{
"HTTP",
HttpParseStart,
HttpParseEnd,
doHttpStart,
doHttpLoop,
doHttpEnd,
HttpStatsFormat,
HttpStatsInit,
HttpStatsUpdate,
HttpStatsOutput,
},
{
"WMAP",
WmapParseStart,
WmapParseEnd,
doWmapStart,
doWmapLoop,
doWmapEnd,
WmapStatsFormat,
WmapStatsInit,
WmapStatsUpdate,
WmapStatsOutput,
},
{
NULL, /* terminate the list */
},
};
/* End of globals */
static time_t ramptime = 0;
static char mailmaster[MAXHOSTNAMELEN];
static NETPORT listenport = 0;
static char *commandsfilename = NULL;
static int f_usestdin = 0;
#if 0
static struct hostent mailserv_phe, mailmast_phe;
static struct protoent mailserv_ppe, mailmast_ppe;
static unsigned long mailserv_addr, mailmast_addr;
static short mailserv_type, mailmast_type; /* socket type */
#endif
static void
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 [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");
fprintf(stderr, " options:\n");
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");
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");
fprintf(stderr, " -v print version\n");
fprintf(stderr, " -r record all transactions\n\n");
exit(1);
} /* END usage() */
void
parseArgs(int argc, char **argv)
{
int getoptch;
extern char *optarg;
extern int optind;
/*
* PARSE THE COMMAND LINE OPTIONS
*/
while((getoptch =
getopt(argc,argv,"hf:H:T:t:u:c:m:M:n:N:R:D:Adrsv")) != EOF)
{
switch(getoptch)
{
case 'h':
usage(argv[0]);
break;
case 'H': /* name for parsing */
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);
break;
case 'd':
gn_debug = 1;
break;
case 'D':
strcpy(gs_dateStamp, optarg);
break;
case 'm':
gn_maxerrorcnt = atoi(optarg);
break;
case 'M':
gn_maxBlockCnt = atoi(optarg);
break;
case 'n':
gn_numprocs = atoi(optarg);
break;
case 'N':
gn_numthreads = atoi(optarg);
break;
case 'u':
commandsfilename = mystrdup(optarg);
break;
case 's':
f_usestdin = 1;
break;
case 't':
gt_testtime = time_atoi(optarg);
break;
case 'R':
ramptime = time_atoi(optarg);
break;
case 'v':
fprintf(stderr, "Netscape " MAILCLIENT_VERSION "\n");
fprintf(stderr, "Copyright (c) Netscape Communications Corporation 1997, 1998, 1999\n");
exit(1);
break;
case 'r':
gn_record_telemetry = 1;
break;
default:
usage(argv[0]);
}
}
}
#define SIZEOF_NTOABUF ((3+1)*4)
char *
safe_inet_ntoa(struct in_addr ina, char *psz)
{
sprintf(psz,"%d.%d.%d.%d",
((unsigned char *)&ina.s_addr)[0],
((unsigned char *)&ina.s_addr)[1],
((unsigned char *)&ina.s_addr)[2],
((unsigned char *)&ina.s_addr)[3]);
return psz;
}
/* look up the host name and protocol
* called from each protocol (via connectsock)
*/
int
resolve_addrs(char *host,
char *protocol,
struct hostent *host_phe,
struct protoent *proto_ppe,
unsigned long *addr,
short *type)
{
struct hostent *phe;
struct protoent *ppe;
#ifdef USE_PTHREADS
#ifdef USE_GETHOSTBYNAME_R
struct hostent he;
struct protoent pe;
char buf[512];
int h_err;
#endif
#endif
/* if IP address given, convert to internal form */
if (host[0] >= '0' && host[0] <= '9') {
*addr = inet_addr(host);
if (*addr == INADDR_NONE)
return(returnerr(stderr,"Invalid IP address %s\n", host));
} else {
/* look up by name */
#ifdef USE_GETHOSTBYNAME_R
phe = gethostbyname_r(host, &he, buf, sizeof(buf), &h_err);
errno = h_err;
#else
phe = gethostbyname(host);
#endif
if (phe == NULL)
{
D_PRINTF(stderr, "Gethostbyname failed: %s", neterrstr() );
return(returnerr(stderr,"Can't get %s host entry\n", host));
}
memcpy(host_phe, phe, sizeof(struct hostent));
memcpy((char *)addr, phe->h_addr, sizeof(*addr));
}
/* Map protocol name to protocol number */
#ifdef USE_GETPROTOBYNAME_R
ppe = getprotobyname_r(protocol, &pe, buf, sizeof(buf));
#else
ppe = getprotobyname(protocol);
#endif
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 */
SOCKET
connectsock(ptcx_t ptcx,
char *host,
resolved_addr_t *hostInfo,
NETPORT portnum,
char *protocol)
{
struct sockaddr_in sin; /* an Internet endpoint address */
SOCKET s; /* socket descriptor */
int type; /* socket type */
short proto;
int returnval; /* temporary return value */
char ntoa_buf[SIZEOF_NTOABUF];
D_PRINTF(debugfile, "Beginning connectsock; host=%s port=%d proto=%s\n",
host, portnum, protocol );
sin.sin_family = AF_INET;
memset((char *)&sin, 0, sizeof(sin));
D_PRINTF(debugfile, "Zeroed address structure\n" );
sin.sin_port = htons(portnum);
D_PRINTF(debugfile, "Set port number %d\n", portnum );
/* check if we've resolved this already */
if ((hostInfo) && (hostInfo->resolved)) {
sin.sin_addr.S_ADDR = hostInfo->host_addr;
sin.sin_family = PF_INET;
proto = hostInfo->host_ppe.p_proto;
type = hostInfo->host_type;
} else {
struct hostent host_phe;
struct protoent host_ppe;
unsigned long host_addr;
short host_type; /* socket type */
if (resolve_addrs(host, "tcp",
&host_phe, &host_ppe, &host_addr, &host_type)) {
return returnerr(debugfile,"Can't resolve hostname %s in get()\n",
host);
}
sin.sin_addr.S_ADDR = host_addr;
sin.sin_family = PF_INET;
proto = host_ppe.p_proto;
type = host_type;
}
/* Allocate a socket */
s = socket(PF_INET, type, proto);
if (BADSOCKET(s))
{
D_PRINTF(debugfile, "Can't create socket: %s\n",neterrstr() );
return BADSOCKET_VALUE;
}
/* Connect the socket */
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);
SET_ERROR(err);
return BADSOCKET_VALUE;
}
/* all done, returning socket descriptor */
D_PRINTF(debugfile, "Returning %d from connectsock call\n", s );
return(s);
} /* END connectsock() */
int
set_abortive_close(SOCKET sock)
{
struct linger linger_opt;
linger_opt.l_onoff = 1;
linger_opt.l_linger = 0;
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;
}
return 0;
}
void
initializeCommands(char *cfilename)
{
char *cbuf = NULL;
int cbuflen = 0;
int cbufalloced = 0;
int ret;
FILE *cfile;
D_PRINTF(stderr, "initializeCommands(%s)\n",
cfilename ? cfilename : "STDIN");
if (cfilename == NULL || strlen(cfilename) == 0) {
cfile = stdin;
cfilename = "stdin";
} else {
if ((cfile = fopen(cfilename, "r")) == NULL) {
D_PRINTF(stderr, "Cannot open commands file %s: errno=%d: %s\n",
cfilename, errno, strerror(errno));
errexit(stderr, "Cannot open commands file %s: errno=%d: %s\n",
cfilename, errno, strerror(errno));
}
}
#define CMDBUF_INCR 4096 /* longest allowed line */
while (!feof(cfile)) { /* read file in to char array */
if ((cbuflen + CMDBUF_INCR + 1) > cbufalloced) { /* grow array */
cbufalloced += CMDBUF_INCR;
cbuf = (char *)myrealloc(cbuf, cbufalloced+1);
cbuf[cbuflen] = '\0';
}
ret = fread(cbuf+cbuflen, 1, CMDBUF_INCR, cfile);
if (ret < 0) {
D_PRINTF(stderr, "Error reading commands file %s: errno=%d: %s\n",
cfilename, errno, strerror(errno));
errexit(stderr, "Error reading commands file %s: errno=%d: %s\n",
cfilename, errno, strerror(errno));
}
if (ret == 0)
break;
cbuflen += ret;
cbuf[cbuflen] = '\0';
}
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);
errexit(stderr, "Could not load command file\n");
}
if (0 == gn_total_weight) {
D_PRINTF(stderr, "No commands found for this host in %s\n", cfilename);
errexit(stderr, "No command for current host in command file\n");
}
}
int
readwriteStream(int ii, int fdin, int fdout)
{
char buf[MAX (8192, 2*SIZEOF_SUMMARYTEXT+1)], *cp;
int res;
int toread = sizeof(buf)-1;
int towrite;
D_PRINTF(stderr, "readwriteStream(%d,%d,%d)\n", ii, fdin, fdout);
/* structured as a while() for future nonblocking style */
while (toread) {
errno = 0;
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 == 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));
return -1;
} else {
/* TODO: ...can do more data reduction here... */
toread -= res;
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);
D_PRINTF(stderr, "wrote %d bytes to %d\n", res, fdout);
if (res <= 0) {
D_PRINTF(stderr, "error writing to %d: errno=%d: %s\n", fdout, errno, strerror(errno));
} else {
towrite -= res;
cp += res;
}
}
}
toread = 0; /* just read one chunk at a time for now... */
}
return 0;
}
#ifdef _WIN32
#define DIRECT_OUT /* report directly to stdout */
int
readwriteChildren(pccx_t pccxs)
{
while (readwriteStream(0, pccxs[0].socket, 1) >= 0)
;
return 0;
}
#else /* !_WIN32 */
/* This is where the master process merges output and waits for
the spawned processes to exit.
Note that no alarm has been set. We never wait very long in poll.
*/
int
readwriteChildren(pccx_t pccxs)
{
struct pollfd *pfds;
int nfds;
int ii;
/*
* Wait for all children to exit.
*/
nfds=0;
pfds = (struct pollfd *)mycalloc(sizeof(struct pollfd)*gn_numprocs);
for (ii=0; ii < gn_numprocs; ++ii) {
if (pccxs[ii].socket != -1) {
pfds[nfds].fd = pccxs[ii].socket;
++nfds;
}
}
fflush(stdout);
while (nfds > 0) {
int ret, closethisfd;
if (time(0L) >= gt_aborttime) {
D_PRINTF (stderr, "Time is up. Signalling exit %d\n",
gf_timeexpired);
gf_timeexpired = EXIT_FASTEST; /* signal clean up and exit */
break; /* just get out of here */
}
for (ii=0; ii < nfds; ++ii) {
pfds[ii].events = POLLIN;
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, ret=%d\n", ret);
if (ret == 0)
continue;
if (ret < 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
fprintf(stderr, "poll error: errno=%d: %s\n", errno, strerror(errno));
break;
}
for (ii = 0; ii < nfds; ++ii) {
closethisfd = 0;
if (pfds[ii].revents) {
D_PRINTF(stderr, "poll says stdout fd=%d for client=%d is 0x%02x\n",
pfds[ii].fd, ii, pfds[ii].revents);
}
if (pfds[ii].revents & POLLIN) {
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",
pfds[ii].fd, ii);
closethisfd = 1;
}
if (closethisfd) {
D_PRINTF(stderr, "closing for slot=%d fd=%d nfds=%d\n",
ii, pfds[ii].fd, nfds);
NETCLOSE(pfds[ii].fd);
--nfds; /* shrink poll array */
/* NOTE: this re-orders the array */
if (ii != nfds) { /* move last one into old spot */
pfds[ii].fd = pfds[nfds].fd;
pfds[ii].events = pfds[nfds].events;
pfds[ii].revents = pfds[nfds].revents;
--ii; /* check moved entry on the next loop */
}
}
}
}
if (nfds > 0) {
d_printf (stderr,
"WARNING: Exiting with open clients nfds=%d time=%lu shutdowntime=%lu\n",
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);
}
}
return 0;
}
#endif /* _WIN32 */
/* This is where each sub process starts */
THREAD_RET
launchChild(void *targ)
{
SOCKET clientsock;
struct sockaddr_in saddr; /* server address */
struct linger linger_opt;
unsigned int testtimeleft;
int ret;
unsigned int thread_stagger_usec = 1000; /* 1000/sec */
int pnum = (int)targ;
gn_myPID = getpid();
if (ramptime) {
/* 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);
} else {
thread_stagger_usec = 0;
}
}
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");
saddr.sin_family = AF_INET;
saddr.sin_port = listenport;
if (connect(clientsock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
NETCLOSE(clientsock);
errexit(stderr, "child connect(): %s\n", neterrstr());
}
#if 1
linger_opt.l_onoff = 1;
linger_opt.l_linger = 60;
if (setsockopt(clientsock, SOL_SOCKET, SO_LINGER, (char *) &linger_opt, sizeof(linger_opt)) < 0) {
NETCLOSE(clientsock);
errexit(stderr, "child setsockopt(): %s\n", neterrstr());
}
#endif
D_PRINTF(stderr, "child %d: using socket %d\n", pnum, clientsock);
#if 0
unsigned int fork_stagger_usec = 10000; /* 100/sec */
if (pnum) {
D_PRINTF(stderr, "child %d: delaying %d secs\n",
pnum, USECS_2_SECS(pnum * fork_stagger_usec));
MS_usleep(pnum * fork_stagger_usec);
}
#endif
testtimeleft = gt_shutdowntime - time(0L);
D_PRINTF(stderr, "child %d: proceeding for %d remaining seconds\n",
pnum, testtimeleft);
if (testtimeleft > 0) {
/* This is where the test gets run */
#ifndef DIRECT_OUT
ret = clientProc(pnum, clientsock,
testtimeleft, thread_stagger_usec);
#else
ret = clientProc(pnum, fileno(stdout),
testtimeleft, thread_stagger_usec);
#endif
} else {
D_PRINTF(stderr, "child %d: Too late to start! shudowntime=%lu now=%lu\n",
pnum, testtimeleft, time(0L));
ret = -1;
}
D_PRINTF(stderr, "child %d: closing logging socket\n", pnum);
NETCLOSE(clientsock);
#ifndef _WIN32
return((void *)ret);
#endif
}
/* Wait for childred to exit (after readwritechildren returns).
*/
int
waitChildren(void)
{
#ifndef _WIN32
int pid;
int status;
for (;;) {
errno = 0;
alarm(gt_stopinterval); /* dont wait forever */
pid = wait(&status);
if (pid == -1) {
if (errno == ECHILD) {
break; /* none left. finished */
}
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;
}
}
}
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 */
return 0;
}
int
main(int argc, char *argv[])
{
int ii;
struct tm *tmptm;
time_t currentTime;
#ifdef _WIN32
int err;
WSADATA WSAData;
#endif
int ret;
int pid=0;
pccx_t pccxs; /* client process contexts */
SOCKET serversock;
struct sockaddr_in saddr; /* server address */
struct sockaddr_in caddr; /* client address */
int addr_len;
char ntoabuf[SIZEOF_NTOABUF];
#ifdef _WIN32
//MessageBeep(~0U); /* announce our existence */
err = WSAStartup(MAKEWORD(1,1), &WSAData);
if (err != 0) {
errexit(stderr, "Error in WSAStartup()\n");
}
atexit(sock_cleanup);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
#endif /* _WIN32 */
gn_myPID = getpid();
gethostname(gs_thishostname, sizeof(gs_thishostname)-1);
memset(mailmaster, 0, sizeof(mailmaster));
memset(gs_dateStamp, 0, DATESTAMP_LEN*sizeof(char));
parseArgs(argc, argv);
returnerr(stderr, MAILCLIENT_VERSION "\n");
returnerr(stderr, "procs=%d threads=%d seconds=%d ramptime=%d...\n",
gn_numprocs, gn_numthreads , gt_testtime, ramptime);
if (ramptime > gt_testtime) {
returnerr (stderr, "RampTime %d longer than TestTime %d. Adjusting.\n",
ramptime, gt_testtime);
ramptime = gt_testtime;
}
D_PRINTF(stderr, "Running in debug mode\n\n" );
/* print the command line */
if (gn_debug) {
for (ii = 0; ii < argc; ii++)
fprintf(stderr, "%s ", argv[ii] );
fprintf(stderr, "\n\n" );
}
if (commandsfilename == NULL && f_usestdin == 0) {
/* Must specify a message list */
returnerr(stderr, "No mail message list specified (use <-s | -u commandsfilename>)\n");
usage(argv[0]);
}
if (gt_testtime == 0) { /* NO TEST TIME */
usage(argv[0]);
}
if (gn_numprocs > MAXPROCSPERNODE || gn_numprocs < 1) {
returnerr(stderr, "Number of clients must be between 1 and %d\n", MAXPROCSPERNODE);
usage(argv[0]);
}
crank_limits();
if (!gs_dateStamp[0]) {
time(&currentTime);
tmptm = localtime(&currentTime);
strftime(gs_dateStamp, DATESTAMP_LEN, "%Y%m%d%H%M%S", tmptm);
}
initializeCommands(commandsfilename); /* read command block */
gt_startedtime = time(0L);
gt_shutdowntime = gt_startedtime + gt_testtime; /* start clean shutdown */
gt_stopinterval = MAX ((ramptime/EXIT_FASTEST), 1); /* signal period */
/* this is when the master gives up on the children */
gt_aborttime = gt_shutdowntime + gt_stopinterval*2*EXIT_FASTEST;
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) {
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);
errexit(stderr, "bind() error: %s\n", neterrstr());
}
if (listen(serversock, 512) == -1) {
NETCLOSE(serversock);
errexit(stderr, "listen() error: %s\n", neterrstr());
}
addr_len = sizeof(saddr);
if (getsockname(serversock, (struct sockaddr *)&saddr, &addr_len) == -1) {
NETCLOSE(serversock);
errexit(stderr, "getsockname() error: %s\n", neterrstr());
}
listenport = saddr.sin_port;
D_PRINTF(stderr, "listening on [%s:%d]\n",
safe_inet_ntoa(saddr.sin_addr, ntoabuf), ntohs(listenport));
setup_signal_handlers (); /* trap signals */
for(ii = 0; ii < gn_numprocs; ++ii) {
D_PRINTF(stderr, "parent: forking client %d\n", ii);
#ifdef _WIN32
if (_beginthread(launchChild, NT_STACKSIZE, (void *)ii) == -1) {
errexit(stderr, "_beginthread failed: %d", GetLastError());
}
#else
#ifdef DIRECT_OUT /* for Unix, only if debugging */
if (1 == gn_numprocs) {
fprintf (stderr, "Single process, NOT forking.\n");
launchChild (0); /* DEBUG */
return 0;
}
#endif
switch(pid=fork()) {
case 0: /* CHILD */
launchChild((void *)ii);
exit(ii);
break;
case -1: /* ERROR */
fprintf(stderr, "parent: error forking child %d, errno=%d: %s\n", ii, errno, strerror(errno));
errexit(stderr, "Error forking child processes\n");
exit(1);
default: /* PARENT */
break;
}
#endif
pccxs[ii].pid = pid;
D_PRINTF(stderr, "parent: Accepting child %d pid=%d\n", ii, pid);
/* Maybe fork everything before accepting */
addr_len = sizeof(caddr);
/* If the the child dies immediately, we hang here */
if ((ret = accept(serversock, (struct sockaddr *)&caddr, &addr_len)) == -1) {
errexit(stderr, "accept() error: %s\n", neterrstr());
}
D_PRINTF(stderr, "parent: child %d using socket %d\n", ii, ret);
pccxs[ii].socket = ret;
}
readwriteChildren(pccxs);
D_PRINTF(stderr, "done polling, now just wait\n");
waitChildren();
returnerr(stderr, "Master process done.\n");
fflush(stdout);
return 0;
} /* end main() */

633
mstone/src/parse.c Normal file
Просмотреть файл

@ -0,0 +1,633 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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 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.
*/
/*
* parse the workload description file
*
*/
#include "bench.h"
/* global variables */
param_list_t *g_default_params; /* list of default values */
/* Find a protocol in the global protocol list */
protocol_t *
protocol_get (char *name)
{
protocol_t *pp;
for (pp=g_protocols; pp->name != NULL; ++pp) {
/* we only check the length of the registered protocol name */
/* that way NAME can have additonal stuff after it */
/* This is much better than the old single letter checking */
if (0 == strnicmp (name, pp->name, strlen (pp->name)))
return pp;
}
return NULL;
}
/*
converts a string of the form #x to seconds
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
time_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 * atoi(pstr);
break;
case 'h': /* hours */
case 'H':
ret = 60 * 60 * atoi(pstr);
break;
case 'm': /* minutes */
case 'M':
ret = 60 * atoi(pstr);
break;
case 's': /* seconds */
case 'S':
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!
*/
param_list_t *
paramListInit (void)
{
param_list_t *np = (param_list_t *)mycalloc (sizeof (param_list_t));
return np;
}
/* paramListAdd returns: 1 update existing value, 0 new, -1 out of memory */
int
paramListAdd (param_list_t *list,
const char *name,
const char *value)
{
param_list_t *pl;
int found = 0;
assert (list != NULL);
assert (name != NULL);
assert (value != NULL);
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 (0 == strcmp (pl->name, name)) {
found = 1;
break;
}
}
if (found) {
free (pl->value);
pl->value = mystrdup (value);
if (NULL == pl->value) return -1; /* out of memory */
return 1;
} else {
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;
}
}
/* paramListGet returns value or NULL */
char *
paramListGet (param_list_t *list,
const char *name)
{
param_list_t *pl;
assert (list != NULL);
assert (name != NULL);
for (pl = list; pl->next; pl = pl->next) {
if (0 == strcmp (pl->name, name)) {
return pl->value;
}
}
return NULL;
}
/*
Simple keyword indexed string storage
This kind of thing has been invented many times. Once more with gusto!
*/
string_list_t *
stringListInit (const char *value)
{
string_list_t *np = (string_list_t *)mycalloc (sizeof (string_list_t));
if (value)
np->value = mystrdup (value); /* This can be NULL */
return np;
}
void
stringListFree (string_list_t *list)
{
string_list_t *pl, *next;
assert (list != NULL);
for (pl = list; pl; pl = next) {
next = pl->next;
if (pl->value)
free (pl->value);
free (pl);
}
}
/* stringListAdd returns: 0 new, -1 out of memory */
int
stringListAdd (string_list_t *list,
const char *value)
{
string_list_t *pl;
string_list_t *np;
assert (list != NULL);
assert (value != NULL);
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 = (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;
}
/* return non 0 if whitespace */
#define IS_WHITE(c) ((' ' == (c)) || '\t' == (c))
#define IS_TERM(c) (('\r' == (c)) || '\n' == (c))
#define IS_NUM(c) (('0' <= (c)) && ('9' >= (c)))
/*
Get a 'line' from a text buffer (terminated by CR-NL or NL)
Handle comments.
Skip empty lines.
Handle continued lines (backslash as last character)
Return the pointer to the next line (or NULL at end)
*/
char *
get_line_from_buffer (char *buffer, /* buffer to sort through */
char *line, /* line buffer to fill in */
int *lineCount, /* count of lines */
int continuation) /* part of previous line */
{
char *end, *start;
char *next;
int len;
assert (buffer != NULL);
assert (line != NULL);
next = strchr (buffer, '\n');
if (next) {
++next; /* start point for next line */
} else if (strlen (buffer) > 0) {
d_printf (stderr, "Last line missing NEWLINE\n");
} else { /* done with buffer */
*line = 0;
return NULL;
}
if (lineCount) ++(*lineCount); /* increment line count */
if (continuation) {
/* continuation lines keep everything */
start = buffer;
end = next-1;
} else {
/* find usefull text */
len = strcspn (buffer, "#\r\n");
if (!len) { /* empty line, go to next */
return get_line_from_buffer (next, line, lineCount, continuation);
}
/* skip trailing white too */
for (end = buffer + len; end > buffer; --end) {
if (!IS_WHITE (end[-1])) break;
}
if (end == buffer) { /* blank line */
return get_line_from_buffer (next, line, lineCount, continuation);
}
/* find leading whitespace */
start = buffer + strspn (buffer, " \t");
}
assert (end > start); /* we should have found blank above */
strncpy(line, start, end - start); /* get a line */
line[end-start] = '\0';
if (line[end-start-1] == '\\') { /* continuation line */
return get_line_from_buffer (next, &line[end-start-1], lineCount, 1);
}
D_PRINTF(stderr, "clean line [%s]\n", line);
return next;
}
/*
return 1 if for us, 0 if everyone, -1 if not for us
*/
int
check_hostname_attribute (const char *line)
{
char *hostp;
/* Section open, check if for us */
if ((hostp = strstr(line, "hosts="))
|| (hostp = strstr(line, "HOSTS="))) {
hostp = strchr (hostp, '='); /* skip to the equals */
assert (hostp != NULL);
/* look for our hostname */
if (strstr(hostp, gs_parsename) != NULL) {
/* should check for complete string match */
return 1;
} else {
return -1;
}
}
/* not host specific */
return 0;
}
/*
Protocol independent parsing
*/
int
cmdParseNameValue (pmail_command_t cmd,
char *name,
char *tok)
{
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);
else if (strcmp(name, "idletime") == 0)
cmd->idleTime = time_atoi(tok);
else if (strcmp(name, "blockid") == 0)
cmd->blockID = time_atoi(tok);
else if (strcmp(name, "blocktime") == 0)
cmd->blockTime = time_atoi(tok);
else if (strcmp(name, "loopdelay") == 0)
cmd->loopDelay = time_atoi(tok);
else if (strcmp(name, "checkmailinterval") == 0) /* BACK COMPAT */
cmd->loopDelay = time_atoi(tok);
else
return 0; /* no match */
return 1; /* matched it */
}
/*
* count_num_commands()
* given a commandsfile string, count the valid command for us.
TODO Dynamically load the protocols found
*/
static int
count_num_commands(char *commands)
{
char *cmdptr = commands;
int num_comms = 0;
char line[LINE_BUFSIZE];
/*
* parse through the string line-by-line,strip out comments
*/
/*D_PRINTF(stderr, "count_num_commands[%s]\n", commands);*/
while (NULL != (cmdptr = get_line_from_buffer (cmdptr, line, NULL, 0))) {
/* increment count if we've hit a open tag (e.g. <SMTP...) and
it's not the <Default> tag, or <Graph> tag */
if (line[0] != '<') continue; /* not an open */
if (line[1] == '/') continue; /* a close */
if (0 == strnicmp (line+1, "default", 7)) continue; /* default */
/* should already be filtered out */
if (0 == strnicmp (line+1, "graph", 5)) continue; /* graph */
/* Section open, check if for us */
if (check_hostname_attribute (line) < 0) {
D_PRINTF (stderr, "count_num_commands: section not for us '%s'\n",
line);
continue;
}
/* find protocol */
if (NULL == protocol_get (line+1)) {
/* TODO load handler */
/* TODO add to protocol list */
D_PRINTF (stderr, "count_num_commands: No handler for '%s'\n",
line);
continue;
}
D_PRINTF(stderr, "count_num_commands: Found section '%s'\n", line);
num_comms++;
}
return (num_comms);
}
char *
string_tolower(char *string)
{
if (string == NULL)
return NULL;
/* convert to lower case */
for (; *string != '\0'; ++string) {
*string = tolower (*string);
}
return string;
}
char *
string_unquote(char *string)
{
int len, num;
char *from, *to;
if (string == NULL)
return NULL;
len = strlen(string);
if (string[0] == '"' && string[len-1] == '"') {
/* remove matching double-quotes */
string[len-1] = '\0';
++string;
}
/* replace quoted characters (and decimal codes) */
/* assuming line-continuation already happened */
from = to = string;
while (*from) {
if (*from == '\\') {
++from;
if (IS_NUM(*from)) {
num = *from++ - '0';
if (IS_NUM(*from))
num = num*10 + (*from++ - '0');
if (IS_NUM(*from))
num = num*10 + (*from++ - '0');
*to++ = num;
} else {
switch (*from) {
case '\0': continue;
case 'n': *to++ = '\n'; break;
case 'r': *to++ = '\r'; break;
case 't': *to++ = '\t'; break;
default: *to++ = *from; break;
}
++from;
}
} else {
*to++ = *from++;
}
}
*to = '\0';
return string;
}
/*
* load_commands()
* Parse the commlist file again, this time getting the commands, filenames
* and weights and reading the message files into memory.
*/
int
load_commands(char *commands)
{
char *cmdptr = commands;
int total_weight = 0;
char line[LINE_BUFSIZE];
int lineNumber = 0;
int commIndex = 0;
int inCommand = 0; /* 0 none, -1 ignore, 1 default, 2 other */
string_list_t *param_list = NULL;
g_default_params = paramListInit (); /* create default section list */
/* set built in defaults. always use lower case names */
paramListAdd (g_default_params, "numloops", "1");
paramListAdd (g_default_params, "numrecipients", "1");
paramListAdd (g_default_params, "numlogins", "1");
paramListAdd (g_default_params, "numaddresses", "1");
paramListAdd (g_default_params, "weight", "100");
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 */
return returnerr (stderr, "No commands found\n");
}
/* allocate structure to hold command list (command filename weight) */
g_loaded_comm_list =
(mail_command_t *) mycalloc(gn_number_of_commands
* sizeof(mail_command_t));
while (NULL
!= (cmdptr = get_line_from_buffer (cmdptr, line, &lineNumber, 0))) {
/* The pre-process step does lots of checking, keep this simple */
/* check for close tag */
if ((line[0] == '<') && (line[1] == '/')) {
/* default or ignored command */
if (inCommand < 2) {
assert (param_list == NULL);
inCommand = 0;
continue;
}
stringListAdd (param_list, line); /* store last line */
if (g_loaded_comm_list[commIndex].proto->parseEnd) {
int ret;
ret = (g_loaded_comm_list[commIndex].proto->parseEnd)
(g_loaded_comm_list+commIndex,
param_list, g_default_params);
if (ret < 0) {
D_PRINTF (stderr, "Error finalizing section for '%s'\n",
line);
continue;
}
}
g_loaded_comm_list[commIndex].proto->cmdCount++;
D_PRINTF (stderr, "Section done: '%s' weight=%d\n\n",
line, g_loaded_comm_list[commIndex].weight);
/* update total weight */
total_weight += g_loaded_comm_list[commIndex].weight;
commIndex++;
inCommand = 0;
if (param_list) {
stringListFree (param_list);
param_list = NULL;
}
continue;
}
/* open tag */
if (line[0] == '<') {
protocol_t *pp;
if (check_hostname_attribute (line) < 0) { /* not for us */
D_PRINTF (stderr, "Section not for us %s\n", line);
inCommand = -1;
continue;
}
/* Check if default special case */
if (0 == strnicmp (line+1, "default", 7)) { /* default */
D_PRINTF (stderr, "DEFAULT section\n");
inCommand = 1;
continue;
}
/* Check if we should ignore it */
if (0 == strnicmp (line+1, "graph", 5)) { /* ignore graph */
D_PRINTF (stderr, "GRAPH section (ignored)\n");
inCommand = -1;
continue;
}
pp = protocol_get (line+1);
if (NULL == pp) { /* protocol not found */
d_printf (stderr,
"Warning: Skipping section with no protocol handler '%s'\n",
line);
continue;
}
if (pp->parseStart) {
int ret;
ret = (pp->parseStart) (g_loaded_comm_list+commIndex,
line, g_default_params);
if (ret < 0) {
D_PRINTF (stderr, "Error Initializing section for '%s'\n",
line);
continue;
} else if (ret == 0) {
D_PRINTF (stderr, "Ignoring section for '%s'\n",
line);
continue;
}
}
/* start a command */
D_PRINTF (stderr, "New Section: %s\n", line);
g_loaded_comm_list[commIndex].proto = pp;
inCommand = 2;
param_list = stringListInit (line); /* store first line */
/* ignoring rest of line */
continue;
}
/* If we're not inside a command tag or not for us, ignore the line */
if (inCommand <= 0) {
continue;
}
/* attr value */
if (1 == inCommand) { /* default, always name value pairs */
char *value;
value = line + strcspn (line, " \t=");
if (value != line) {
*value++ = 0; /* terminate name */
value += strspn(value, " \t=");
string_tolower(line);
value = string_unquote(value);
/*D_PRINTF (stderr, "DEFAULT: name='%s' value='%s'\n",
line, value);*/
paramListAdd (g_default_params, line, value);
} else {
D_PRINTF (stderr, "DEFAULT: Cound not find 'NAME VALUE...', line %d\n",
lineNumber);
}
continue;
}
/* store body for protocol parsing */
stringListAdd (param_list, line);
}
return (total_weight);
}

99
mstone/src/pish.h Normal file
Просмотреть файл

@ -0,0 +1,99 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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 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.
*/
/* these are protocol dependent timers for Pop, Imap, Smtp, Http*/
typedef struct pish_stats {
event_timer_t connect;
event_timer_t banner;
event_timer_t login;
event_timer_t cmd;
event_timer_t msgread;
event_timer_t msgwrite;
event_timer_t logout;
/* protocol dependent local storage */
/* should have local ranges too */
range_t loginRange; /* login range for this thread */
unsigned long lastLogin;
range_t domainRange; /* domain range for this thread */
unsigned long lastDomain;
range_t addressRange; /* address range for this thread */
unsigned long lastAddress;
} pish_stats_t;
/* These are common to POP, IMAP, SMTP, HTTP */
typedef struct pish_command {
char * mailServer;
resolved_addr_t hostInfo; /* should be a read only cache */
NETPORT portNum;
/* These are common to SMTP, POP, IMAP */
char * loginFormat;
range_t loginRange; /* login range for all threads */
range_t domainRange; /* domain range for all threads */
char * passwdFormat;
/* SMTP command attrs */
char * addressFormat;
range_t addressRange; /* address range for all threads */
char * smtpMailFrom;
char * filename;
int numRecipients; /* recpients per message */
int msgsize; /* message size without trailing CRLF.CRLF */
char * msgdata; /* cache the file in mem */
int useEHLO; /* use EHLO instead of HELO */
int useAUTHLOGIN; /* use AUTH LOGIN to authenticate */
int useAUTHPLAIN; /* use AUTH PLAIN to authenticate */
/* POP/IMAP flag to leave mail on server */
int leaveMailOnServer; /* IMAP > 2: leave unseen */
/* IMAP command attrs */
char * imapSearchFolder;
char * imapSearchPattern;
int imapSearchRate;
/* HTTP command */
char * httpCommand;
/* WMAP command */
char * wmapCommand;
} pish_command_t;
/* TRANSITION functions */
extern int pishParseNameValue (pmail_command_t cmd, char *name, char *tok);

420
mstone/src/pop3.c Normal file
Просмотреть файл

@ -0,0 +1,420 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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): Dan Christian <robodan@netscape.com>
* Marcel DePaolis <marcel@netcape.com>
* Mike Blakely
*
* 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.
*/
/* pop3.c: POP3 protocol test */
#include "bench.h"
#include "pish.h"
typedef struct _doPOP3_state {
int numMsgs; /* messages in folder */
int totalMsgLength; /* total msg length */
int msgCounter; /* count in download */
} doPOP3_state_t;
static void doPop3Exit (ptcx_t ptcx, doPOP3_state_t *me);
static int
PopParseNameValue (pmail_command_t cmd,
char *name,
char *tok)
{
pish_command_t *pish = (pish_command_t *)cmd->data;
/* find a home for the attr/value */
if (pishParseNameValue(cmd, name, tok) == 0)
; /* done */
else if (strcmp(name, "leavemailonserver") == 0)
pish->leaveMailOnServer = atoi(tok);
else {
return -1;
}
return 0;
}
/*
Set defaults in command structure
*/
int
Pop3ParseStart (pmail_command_t cmd,
char *line,
param_list_t *defparm)
{
param_list_t *pp;
pish_command_t *pish = (pish_command_t *)mycalloc
(sizeof (pish_command_t));
cmd->data = pish;
cmd->numLoops = 9999; /* default 9999 downloads */
pish->portNum = POP3_PORT; /* default port */
D_PRINTF(stderr, "Pop3 Assign defaults\n");
/* Fill in defaults first, ignore defaults we dont use */
for (pp = defparm; pp; pp = pp->next) {
(void)PopParseNameValue (cmd, pp->name, pp->value);
}
return 1;
}
/*
Fill in command structure from a list of lines
*/
int
Pop3ParseEnd (pmail_command_t cmd,
string_list_t *section,
param_list_t *defparm)
{
string_list_t *sp;
pish_command_t *pish = (pish_command_t *)cmd->data;
/* Now parse section lines */
D_PRINTF(stderr, "Pop3 Assign section lines\n");
/* 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 (PopParseNameValue (cmd, name, tok) < 0) {
/* not a known attr */
D_PRINTF(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 (!pish->mailServer) {
D_PRINTF(stderr,"missing server for command");
return returnerr(stderr,"missing server for command\n");
}
if (!pish->loginFormat) {
D_PRINTF(stderr,"missing loginFormat for command");
return returnerr(stderr,"missing loginFormat for command\n");
}
if (!pish->passwdFormat) {
D_PRINTF(stderr,"missing passwdFormat for command");
return returnerr(stderr,"missing passwdFormat for command\n");
}
/* see if we can resolve the mailserver addr */
if (resolve_addrs(pish->mailServer, "tcp",
&(pish->hostInfo.host_phe),
&(pish->hostInfo.host_ppe),
&(pish->hostInfo.host_addr),
&(pish->hostInfo.host_type))) {
return returnerr (stderr, "Error resolving hostname '%s'\n",
pish->mailServer);
} else {
pish->hostInfo.resolved = 1; /* mark the hostInfo resolved */
}
rangeSetFirstCount (&pish->loginRange, pish->loginRange.first,
pish->loginRange.span, pish->loginRange.sequential);
rangeSetFirstCount (&pish->domainRange, pish->domainRange.first,
pish->domainRange.span, pish->domainRange.sequential);
return 1;
}
int
doPopCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen)
{
int rc;
T_PRINTF(ptcx->logfile, command, strlen (command), "POP3 SendCommand");
rc = doCommandResponse(ptcx, sock, command, response, resplen);
if (rc == -1)
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); */
if (strncmp(response, "+OK", 3) != 0) {
if (gf_timeexpired < EXIT_FAST) {
trimEndWhite (command);
trimEndWhite (response);
returnerr(debugfile,"POP3 error command=[%s] response=[%s]\n",
command, response);
}
return -1;
}
return 0;
}
int
popLogin(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock)
{
char command[MAX_COMMAND_LEN];
char respBuffer[MAX_RESPONSE_LEN];
char mailUser[MAX_MAILADDR_LEN];
char userPasswd[MAX_MAILADDR_LEN];
unsigned long loginNum;
unsigned long domainNum;
int rc;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
pish_command_t *pish = (pish_command_t *)cmd->data;
/* generate a random username and domainname(with a mailbox on the server) */
domainNum = rangeNext (&stats->domainRange, stats->lastDomain);
stats->lastDomain = domainNum;
loginNum = rangeNext (&stats->loginRange, stats->lastLogin);
stats->lastLogin = loginNum;
sprintf(mailUser, pish->loginFormat, loginNum, domainNum);
D_PRINTF(debugfile,"mailUser=%s\n", mailUser);
sprintf(command, "USER %s%s", mailUser, CRLF);
event_start(ptcx, &stats->cmd);
rc = doPopCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->cmd);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->login.errs++;
/* error already displayed */
}
return -1;
}
/* send Password */
sprintf(userPasswd, pish->passwdFormat, loginNum);
sprintf(command, "PASS %s%s", userPasswd, CRLF);
event_start(ptcx, &stats->login);
rc = doPopCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->login);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->login.errs++;
returnerr(debugfile,"POP3 cannot login user=%s pass=%s\n",
mailUser, userPasswd);
}
return -1;
}
return 0;
}
void *
doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
{
doPOP3_state_t *me = (doPOP3_state_t *)mycalloc (sizeof (doPOP3_state_t));
char respBuffer[MAX_RESPONSE_LEN];
int rc;
int numBytes;
char command[MAX_COMMAND_LEN];
NETPORT port;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
pish_command_t *pish = (pish_command_t *)cmd->data;
if (!me) return NULL;
me->numMsgs = 0;
me->totalMsgLength = 0;
me->msgCounter = 0;
port = pish->portNum;
event_start(ptcx, &stats->connect);
ptcx->sock = connectsock(ptcx, pish->mailServer, &pish->hostInfo, port, "tcp");
event_stop(ptcx, &stats->connect);
if (BADSOCKET(ptcx->sock)) {
if (gf_timeexpired < EXIT_FAST) {
stats->connect.errs++;
returnerr(debugfile, "POP3 Couldn't connect to %s: %s\n",
pish->mailServer, neterrstr());
}
myfree (me);
return NULL;
}
if (gf_abortive_close) {
if (set_abortive_close(ptcx->sock) != 0) {
returnerr (debugfile, "POP3: WARNING: Could not set abortive close\n");
}
}
/* READ connect response from server */
event_start(ptcx, &stats->banner);
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,"POP3 Error reading banner: %s\n",
neterrstr());
}
doPop3Exit (ptcx, me);
return NULL;
}
/*
* LOGIN
*/
rc = popLogin(ptcx, cmd, ptimer, ptcx->sock);
if (rc != 0) {
doPop3Exit (ptcx, me);
return NULL;
}
/* send a STAT */
sprintf(command, "STAT%s", 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;
}
/* parse number of msgs out of buffer */
if (!sscanf(respBuffer, "+OK %d %d", &me->numMsgs, &me->totalMsgLength)) {
if (gf_timeexpired < EXIT_FAST) {
stats->cmd.errs++;
returnerr(debugfile,"POP3 Error parsing STAT response, %s: %s\n",
respBuffer, neterrstr());
}
doPop3Exit (ptcx, me);
return NULL;
}
D_PRINTF(debugfile,"STAT shows %d msgs of %d total bytes\n",
me->numMsgs, me->totalMsgLength);
return me;
}
int
doPop3Loop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
{
doPOP3_state_t *me = (doPOP3_state_t *)mystate;
char command[MAX_COMMAND_LEN];
char respBuffer[MAX_RESPONSE_LEN];
int rc, numBytes;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
pish_command_t *pish = (pish_command_t *)cmd->data;
if (me->msgCounter >= me->numMsgs) return -1; /* done, close */
/* retr the msgs */
/* send the RETR command */
sprintf(command, "RETR %d%s", ++me->msgCounter, CRLF);
event_start(ptcx, &stats->msgread);
rc = sendCommand(ptcx, ptcx->sock, command);
if (rc == -1) {
event_stop(ptcx, &stats->msgread);
if (gf_timeexpired < EXIT_FAST) {
stats->msgread.errs++;
returnerr(debugfile,"POP3 Error sending RETR %d command: %s\n",
me->msgCounter, neterrstr());
}
doPop3Exit (ptcx, me);
return -1;
}
/* read msg */
numBytes = retrMsg(ptcx, NULL, 0 , ptcx->sock);
event_stop(ptcx, &stats->msgread);
if (numBytes <= 0) {
if (gf_timeexpired < EXIT_FAST) {
stats->msgread.errs++;
returnerr(debugfile,"POP3 Error retrieving msg %d: %s\n",
me->msgCounter, neterrstr());
}
doPop3Exit (ptcx, me);
return -1;
}
/* if we're not told to leave mail on server, delete the message */
if (!pish->leaveMailOnServer) {
/* send the DELE command */
sprintf(command, "DELE %d%s", me->msgCounter, 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 -1;
}
}
return 0;
}
void
doPop3End(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
{
doPOP3_state_t *me = (doPOP3_state_t *)mystate;
char command[MAX_COMMAND_LEN];
char respBuffer[MAX_RESPONSE_LEN];
int rc;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
if (BADSOCKET(ptcx->sock)) return; /* closed by previous error */
/* send QUIT */
sprintf(command, "QUIT%s", CRLF);
event_start(ptcx, &stats->logout);
rc = doPopCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->logout);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->logout.errs++; /* counted twice? */
}
}
doPop3Exit (ptcx, me);
}
void
doPop3Exit (ptcx_t ptcx, doPOP3_state_t *me)
{
if (!BADSOCKET(ptcx->sock))
NETCLOSE(ptcx->sock);
ptcx->sock = BADSOCKET_VALUE;
myfree (me);
}

928
mstone/src/smtp.c Normal file
Просмотреть файл

@ -0,0 +1,928 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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): Dan Christian <robodan@netscape.com>
* Marcel DePaolis <marcel@netcape.com>
* Mike Blakely
*
* 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.
*/
/* SMTP protocol tests */
#include "bench.h"
#include "pish.h"
#define MAXCOMMANDLEN 256
typedef struct _doSMTP_state {
int nothing;
} doSMTP_state_t;
static void doSMTPExit (ptcx_t ptcx, doSMTP_state_t *me);
/*
Set defaults in command structure
*/
int
SmtpParseStart (pmail_command_t cmd,
char *line,
param_list_t *defparm)
{
param_list_t *pp;
pish_command_t *pish = (pish_command_t *)mycalloc
(sizeof (pish_command_t));
cmd->data = pish;
cmd->numLoops = 1; /* default 1 message */
pish->portNum = SMTP_PORT; /* get default port */
D_PRINTF(stderr, "Smtp Assign defaults\n");
/* Fill in defaults first, ignore defaults we dont use */
for (pp = defparm; pp; pp = pp->next) {
(void)pishParseNameValue (cmd, pp->name, pp->value);
}
return 1;
}
/*
Fill in command structure from a list of lines
*/
int
SmtpParseEnd (pmail_command_t cmd,
string_list_t *section,
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 */
D_PRINTF(stderr, "Smtp Assign section lines\n");
/* 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 (pishParseNameValue (cmd, name, tok) < 0) {
/* not a known attr */
D_PRINTF(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 (!pish->mailServer) {
D_PRINTF(stderr,"missing server for command");
return returnerr(stderr,"missing server for command\n");
}
if (!pish->loginFormat) {
D_PRINTF(stderr,"missing loginFormat for command");
return returnerr(stderr,"missing loginFormat for command\n");
}
if (!pish->passwdFormat) {
D_PRINTF(stderr,"missing passwdFormat for command");
return returnerr(stderr,"missing passwdFormat for command\n");
}
if (!pish->addressFormat) {
D_PRINTF(stderr,"missing addressFormat for command");
return returnerr(stderr,"missing addressFormat for command\n");
}
/* check for required attrs */
if (!pish->filename) {
D_PRINTF(stderr,"missing file for SMTP command");
return returnerr(stderr,"missing file for SMTP command\n");
}
/* 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 */
#define MSG_TRAILER CRLF "." CRLF
pish->msgsize = statbuf.st_size;
pish->msgdata = (char *) mycalloc(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);
/* see if we can resolve the mailserver addr */
if (resolve_addrs(pish->mailServer, "tcp",
&(pish->hostInfo.host_phe),
&(pish->hostInfo.host_ppe),
&(pish->hostInfo.host_addr),
&(pish->hostInfo.host_type))) {
return returnerr (stderr, "Error resolving hostname '%s'\n",
pish->mailServer);
} else {
pish->hostInfo.resolved = 1; /* mark the hostInfo resolved */
}
rangeSetFirstCount (&pish->loginRange, pish->loginRange.first,
pish->loginRange.span, pish->loginRange.sequential);
rangeSetFirstCount (&pish->domainRange, pish->domainRange.first,
pish->domainRange.span, pish->domainRange.sequential);
rangeSetFirstCount (&pish->addressRange, pish->addressRange.first,
pish->addressRange.span, pish->addressRange.sequential);
return 1;
}
/* ======================================================================
These routine will become protcol specific.
Since SMTP is the most complex, they are here for now.
*/
/*
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,
char *tok)
{
pish_command_t *pish = (pish_command_t *)cmd->data;
D_PRINTF (stderr, "pishParseNameValue(name='%s' value='%s')\n", name, tok);
/* find a home for the attr/value */
if (cmdParseNameValue(cmd, name, tok))
; /* done */
else if (strcmp(name, "server") == 0)
pish->mailServer = mystrdup (tok);
else if (strcmp(name, "smtpmailfrom") == 0)
pish->smtpMailFrom = mystrdup (tok);
else if (strcmp(name, "loginformat") == 0)
pish->loginFormat = mystrdup (tok);
else if (strcmp(name, "addressformat") == 0)
pish->addressFormat = mystrdup (tok);
else if (strcmp(name, "firstlogin") == 0)
pish->loginRange.first = atoi(tok);
else if (strcmp(name, "numlogins") == 0)
pish->loginRange.span = atoi(tok);
else if (strcmp(name, "sequentiallogins") == 0)
pish->loginRange.sequential = atoi(tok);
else if (strcmp(name, "firstdomain") == 0)
pish->domainRange.first = atoi(tok);
else if (strcmp(name, "numdomains") == 0)
pish->domainRange.span = atoi(tok);
else if (strcmp(name, "sequentialdomains") == 0)
pish->domainRange.sequential = atoi(tok);
else if (strcmp(name, "firstaddress") == 0)
pish->addressRange.first = atoi(tok);
else if (strcmp(name, "numaddresses") == 0)
pish->addressRange.span = atoi(tok);
else if (strcmp(name, "sequentialaddresses") == 0)
pish->addressRange.sequential = atoi(tok);
else if (strcmp(name, "portnum") == 0)
pish->portNum = atoi(tok);
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= mystrdup (tok);
else if (strcmp(name, "httpcommand") == 0)
pish->httpCommand = mystrdup (tok);
else if (strcmp(name, "wmapcommand") == 0)
pish->wmapCommand = mystrdup (tok);
else if (strcmp(name, "passwdformat") == 0)
pish->passwdFormat = mystrdup (tok);
else if (strcmp(name, "searchfolder") == 0)
pish->imapSearchFolder = mystrdup (tok);
else if (strcmp(name, "searchpattern") == 0)
pish->imapSearchPattern = mystrdup (tok);
else if (strcmp(name, "searchrate") == 0)
pish->imapSearchRate = atoi(tok);
else if (strcmp(name, "useehlo") == 0)
pish->useEHLO = atoi(tok);
else if (strcmp(name, "useauthlogin") == 0)
pish->useAUTHLOGIN = atoi(tok);
else if (strcmp(name, "useauthplain") == 0)
pish->useAUTHPLAIN = atoi(tok);
else {
return -1;
}
return 0;
}
/* PROTOCOL specific */
void
pishStatsInit(mail_command_t *cmd, cmd_stats_t *p, int procNum, int threadNum)
{
assert (NULL != p);
if (!p->data) { /* create it */
p->data = mycalloc (sizeof (pish_stats_t));
} else { /* zero it */
memset (p->data, 0, sizeof (pish_stats_t));
}
if (cmd) { /* do sub-range calulations */
pish_command_t *pish = (pish_command_t *)cmd->data;
pish_stats_t *stats = (pish_stats_t *)p->data;
rangeSplit (&pish->loginRange, &stats->loginRange,
procNum, threadNum);
rangeSplit (&pish->domainRange, &stats->domainRange,
procNum, threadNum);
rangeSplit (&pish->addressRange, &stats->addressRange,
procNum, threadNum);
/* initialize sequential range */
stats->lastLogin = (stats->loginRange.sequential < 0)
? stats->loginRange.last+1 : stats->loginRange.first-1;
stats->lastDomain = (stats->domainRange.sequential < 0)
? stats->domainRange.last+1 : stats->domainRange.first-1;
stats->lastAddress = (stats->addressRange.sequential < 0)
? stats->addressRange.last+1 : stats->addressRange.first-1;
}
}
/* PROTOCOL specific */
void
pishStatsUpdate(protocol_t *proto,
cmd_stats_t *sum,
cmd_stats_t *incr)
{
pish_stats_t *ss = (pish_stats_t *)sum->data;
pish_stats_t *is = (pish_stats_t *)incr->data;
event_sum(&sum->idle, &incr->idle);
event_sum(&ss->connect, &is->connect);
event_sum(&ss->banner, &is->banner);
event_sum(&ss->login, &is->login);
event_sum(&ss->cmd, &is->cmd);
event_sum(&ss->msgread, &is->msgread);
event_sum(&ss->msgwrite, &is->msgwrite);
event_sum(&ss->logout, &is->logout);
event_reset(&incr->combined); /* figure out total */
event_sum(&incr->combined, &incr->idle);
event_sum(&incr->combined, &is->connect);
event_sum(&incr->combined, &is->banner);
event_sum(&incr->combined, &is->login);
event_sum(&incr->combined, &is->cmd);
event_sum(&incr->combined, &is->msgread);
event_sum(&incr->combined, &is->msgwrite);
event_sum(&incr->combined, &is->logout);
event_sum(&sum->combined, &incr->combined); /* add our total to sum-total*/
sum->totalerrs += incr->totalerrs;
sum->totalcommands += incr->totalcommands;
}
/* PROTOCOL specific */
void
pishStatsOutput(protocol_t *proto,
cmd_stats_t *ptimer,
char *buf)
{
char eventtextbuf[SIZEOF_EVENTTEXT];
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
*buf = 0;
/* blocks=%ld is handled for us */
/* output proto independent total */
event_to_text(&ptimer->combined, eventtextbuf);
sprintf(&buf[strlen(buf)], "total=%s ", eventtextbuf);
event_to_text(&stats->connect, eventtextbuf);
sprintf(&buf[strlen(buf)], "conn=%s ", eventtextbuf);
event_to_text(&stats->banner, eventtextbuf);
sprintf(&buf[strlen(buf)], "banner=%s ", eventtextbuf);
event_to_text(&stats->login, eventtextbuf);
sprintf(&buf[strlen(buf)], "login=%s ", eventtextbuf);
event_to_text(&stats->cmd, eventtextbuf);
sprintf(&buf[strlen(buf)], "cmd=%s ", eventtextbuf);
event_to_text(&stats->msgwrite, eventtextbuf);
sprintf(&buf[strlen(buf)], "submit=%s ", eventtextbuf);
event_to_text(&stats->msgread, eventtextbuf);
sprintf(&buf[strlen(buf)], "retrieve=%s ", eventtextbuf);
event_to_text(&stats->logout, eventtextbuf);
sprintf(&buf[strlen(buf)], "logout=%s ", eventtextbuf);
/* output proto independent idle */
event_to_text(&ptimer->idle, eventtextbuf);
sprintf(&buf[strlen(buf)], "idle=%s ", eventtextbuf);
}
/* PROTOCOL specific */
void
pishStatsFormat (protocol_t *pp,
const char *extra, /* extra text to insert (client=) */
char *buf)
{
static char *timerList[] = { /* must match order of StatsOutput */
"total",
"conn", "banner", "login", "cmd", "submit", "retrieve", "logout",
"idle" };
char **tp;
char *cp = buf;
int ii;
/* Define the contents of each timer
These must all the same, to that the core time functions
can be qualified. We specify each one for reduce.pl to work right.
*/
for (ii=0, tp=timerList;
ii < (sizeof (timerList)/sizeof (timerList[0]));
++ii, ++tp) {
sprintf(cp, "<FORMAT %s TIMER=[%s]>%s</FORMAT>\n",
extra, *tp,
gs_eventToTextFormat); /* match event_to_text*/
for (; *cp; ++cp); /* skip to the end of the string */
}
/* BUG blocks matches clientSummary */
sprintf(cp, "<FORMAT %s PROTOCOL={%s}>blocks=blocks ",
extra, pp->name);
for (; *cp; ++cp); /* skip to the end of the string */
for (ii=0, tp=timerList; /* same as above list (for now) */
ii < (sizeof (timerList)/sizeof (timerList[0]));
++ii, ++tp) {
sprintf (cp, "%s=[%s] ", *tp, *tp);
for (; *cp; ++cp); /* skip to the end of the string */
}
strcat (cp, "</FORMAT>\n");
}
/*
Actual protocol handling code
*/
int
isSmtpResponseOK(char * s)
{
if (s[0] == '2' || s[0] == '3')
return 1;
return 0;
}
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 == -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;
}
return 0;
}
static const char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int
str_to_base64(const char *str, unsigned int len, char *buf, unsigned int buflen)
{
unsigned int bufused = 0;
int c1, c2, c3;
while (len) {
if (bufused >= buflen-4) {
/* out of space */
return -1;
}
c1 = (unsigned char)*str++;
buf[bufused++] = basis_64[c1>>2];
if (--len == 0) c2 = 0;
else c2 = (unsigned char)*str++;
buf[bufused++] = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
if (len == 0) {
buf[bufused++] = '=';
buf[bufused++] = '=';
break;
}
if (--len == 0) c3 = 0;
else c3 = (unsigned char)*str++;
buf[bufused++] = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
if (len == 0) {
buf[bufused++] = '=';
break;
}
--len;
buf[bufused++] = basis_64[c3 & 0x3F];
}
if (bufused >= buflen-2) {
/* out of space */
return -1;
}
buf[bufused] = '\0';
return bufused;
}
int
smtpAuthPlain(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock)
{
char command[MAX_COMMAND_LEN];
char respBuffer[MAX_RESPONSE_LEN];
char mailUser[MAX_MAILADDR_LEN];
char userPasswd[MAX_MAILADDR_LEN];
unsigned long loginNum;
unsigned long domainNum;
char auth_msg[1024];
int auth_msg_len=0;
char base64_buf[1024];
int rc;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
pish_command_t *pish = (pish_command_t *)cmd->data;
/* generate a random username (with a mailbox on the server) */
domainNum = rangeNext (&stats->domainRange, stats->lastDomain);
stats->lastDomain = domainNum;
loginNum = rangeNext (&stats->loginRange, stats->lastLogin);
stats->lastLogin = loginNum;
sprintf(mailUser, pish->loginFormat, loginNum, domainNum);
sprintf(userPasswd, pish->passwdFormat, loginNum);
D_PRINTF(debugfile,"mailUser=[%.64s]\n", mailUser);
sprintf(command, "AUTH PLAIN%s", CRLF);
event_start(ptcx, &stats->cmd);
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->cmd);
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", /* ??? */
ptcx->errMsg, command, respBuffer);
}
return -1;
}
/* should now have a 3xx continue code */
/* authenticate id */
strcpy(auth_msg, ""); /* who you want to be (must have rights to do this) */
auth_msg_len += strlen("");
auth_msg[auth_msg_len++] = '\0';
/* authorize id */
strcpy(auth_msg + auth_msg_len, mailUser); /* who you are */
auth_msg_len += strlen(mailUser);
auth_msg[auth_msg_len++] = '\0';
/* password */
strcpy(auth_msg + auth_msg_len, userPasswd); /* your credentials */
auth_msg_len += strlen(userPasswd);
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", ptcx->errMsg, mailUser); /* ??? */
return -1;
}
sprintf(command, "%s%s", base64_buf, CRLF);
event_start(ptcx, &stats->login);
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->login);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->login.errs++;
strcat (ptcx->errMsg, "<SmtpLogin: failure sending auth message");
returnerr(debugfile,"%s [%.199s]\n", ptcx->errMsg, mailUser); /* ??? */
}
return -1;
}
/* should look for 2xx code for ok, 4xx is ldap error, 5xx means invalid login */
return 0;
}
int
smtpAuthLogin(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, SOCKET sock)
{
char command[MAX_COMMAND_LEN];
char respBuffer[MAX_RESPONSE_LEN];
char mailUser[MAX_MAILADDR_LEN];
char userPasswd[MAX_MAILADDR_LEN];
unsigned long loginNum;
unsigned long domainNum;
char base64_buf[1024];
int rc;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
pish_command_t *pish = (pish_command_t *)cmd->data;
/* generate a random username (with a mailbox on the server) */
domainNum = rangeNext (&stats->domainRange, stats->lastDomain);
stats->lastDomain = domainNum;
loginNum = rangeNext (&stats->loginRange, stats->lastLogin);
stats->lastLogin = loginNum;
sprintf(mailUser, pish->loginFormat, loginNum, domainNum);
sprintf(userPasswd, pish->passwdFormat, loginNum);
D_PRINTF(debugfile,"mailUser=[%.64s]\n", mailUser);
sprintf(command, "AUTH LOGIN%s", CRLF);
event_start(ptcx, &stats->cmd);
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->cmd);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->login.errs++;
strcat (ptcx->errMsg, "<SmtpLogin: failure sending AUTH LOGIN");
trimEndWhite (command);
returnerr(debugfile, "%s command=[%.99s] response=[%.99s]\n", /* ??? */
ptcx->errMsg, command, respBuffer);
}
return -1;
}
/* should now have a 3xx continue code */
if (str_to_base64(mailUser, strlen(mailUser),
base64_buf, sizeof(base64_buf)) == -1) {
stats->login.errs++;
strcpy (ptcx->errMsg, "SmtpLogin: Internal error encoding user");
returnerr(debugfile, "%s [%.199s]\n", ptcx->errMsg, mailUser); /* ??? */
return -1;
}
sprintf(command, "%s%s", base64_buf, CRLF);
event_start(ptcx, &stats->cmd);
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->cmd);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->login.errs++;
strcat (ptcx->errMsg, "<SmtpLogin: failure sending user");
returnerr(debugfile,"%s [%.199s]\n", ptcx->errMsg, mailUser); /* ??? */
}
return -1;
}
/* should now have a 3xx continue code */
if (str_to_base64(userPasswd, strlen(userPasswd),
base64_buf, sizeof(base64_buf)) == -1) {
stats->login.errs++;
strcpy (ptcx->errMsg, "SmtpLogin: Internal error encoding password");
returnerr(debugfile, "%s [%.199s]\n", ptcx->errMsg, userPasswd); /* ??? */
return -1;
}
sprintf(command, "%s%s", base64_buf, CRLF);
event_start(ptcx, &stats->login);
rc = doSmtpCommandResponse(ptcx, sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->login);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->login.errs++;
strcat (ptcx->errMsg, "<SmtpLogin: failure sending password");
returnerr(debugfile,"%s user=%.99s pass=%.99s\n", /* ??? */
ptcx->errMsg, mailUser, userPasswd);
}
return -1;
}
/* should look for 2xx code for ok, 4xx is ldap error, 5xx means invalid login */
return 0;
}
/* Entry point for running tests */
void *
sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
{
doSMTP_state_t *me = (doSMTP_state_t *)mycalloc (sizeof (doSMTP_state_t));
char respBuffer[MAX_RESPONSE_LEN];
char command[MAXCOMMANDLEN];
int numBytes;
int rc;
pish_command_t *pish = (pish_command_t *)cmd->data;
NETPORT port = pish->portNum;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
if (!me) return NULL;
event_start(ptcx, &stats->connect);
ptcx->sock = connectsock(ptcx, pish->mailServer, &pish->hostInfo, port, "tcp");
event_stop(ptcx, &stats->connect);
if (BADSOCKET(ptcx->sock)) {
if (gf_timeexpired < EXIT_FAST) {
stats->connect.errs++;
returnerr(debugfile, "%s SMTP Couldn't connect to %s: %s\n",
ptcx->errMsg, pish->mailServer, neterrstr());
}
myfree (me);
return NULL;
}
if (gf_abortive_close) {
if (set_abortive_close(ptcx->sock) != 0) {
returnerr (debugfile, "SMTP: WARNING: Could not set abortive close\n");
}
}
/* READ connect response from server */
event_start(ptcx, &stats->banner);
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->useEHLO != 0) {
/* send extended EHLO */
sprintf(command, "EHLO %s%s", gs_thishostname, CRLF);
} else {
/* send normal HELO */
sprintf(command, "HELO%s", CRLF);
}
event_start(ptcx, &stats->cmd);
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->cmd);
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->useAUTHPLAIN) {
/* look for AUTH PLAIN LOGIN in respBuffer */
if (strstr(respBuffer, "AUTH PLAIN LOGIN") != NULL) {
/* FIX: time get base64 time and multiple round trips */
rc = smtpAuthPlain(ptcx, cmd, ptimer, ptcx->sock);
if (rc != 0) {
doSMTPExit (ptcx, me);
return NULL;
}
}
} else if (pish->useAUTHLOGIN) {
/* look for AUTH LOGIN in respBuffer */
if (strstr(respBuffer, "AUTH=LOGIN") != NULL) {
/* FIX: time get base64 time and multiple round trips */
rc = smtpAuthLogin(ptcx, cmd, ptimer, ptcx->sock);
if (rc != 0) {
doSMTPExit (ptcx, me);
return NULL;
}
}
}
return me;
}
/*
* SEND A MESSAGE
*/
int
sendSMTPLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
{
doSMTP_state_t *me = (doSMTP_state_t *)mystate;
char command[MAXCOMMANDLEN];
char respBuffer[MAX_RESPONSE_LEN];
char rcptToUser[MAX_MAILADDR_LEN];
int rc, jj;
long addressNum;
long domainNum;
int numBytes;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
pish_command_t *pish = (pish_command_t *)cmd->data;
/* send MAIL FROM:<username> */
sprintf(command, "MAIL FROM:<%s>%s", pish->smtpMailFrom, CRLF);
event_start(ptcx, &stats->cmd);
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->cmd);
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",
ptcx->errMsg, command, respBuffer);
}
doSMTPExit (ptcx, me);
return -1;
}
/* send RCPT TO:<username> for each recipient */
for (jj = 0; jj < pish->numRecipients; jj++) {
/* generate a random recipient (but with an account on the server) */
domainNum = rangeNext (&stats->domainRange, stats->lastDomain);
stats->lastDomain = domainNum;
addressNum = rangeNext (&stats->addressRange, stats->lastAddress);
stats->lastAddress = addressNum;
sprintf(rcptToUser, pish->addressFormat, addressNum, domainNum);
D_PRINTF(debugfile,"rcptToUser=%s\n", rcptToUser);
sprintf(command, "RCPT TO:<%s>%s", rcptToUser, CRLF);
event_start(ptcx, &stats->cmd);
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->cmd);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->cmd.errs++;
trimEndWhite (command);
returnerr(debugfile, "%s SMTP RCPT [%.99s], ERROR reading [%.99s] response [%.99s]\n",
ptcx->errMsg, command, respBuffer);
}
doSMTPExit (ptcx, me);
return -1;
}
}
/* send DATA */
event_start(ptcx, &stats->cmd);
sprintf(command, "DATA%s", CRLF);
event_stop(ptcx, &stats->cmd);
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",
ptcx->errMsg, respBuffer);
}
doSMTPExit (ptcx, me);
return -1;
}
D_PRINTF(debugfile, "data response %s\n", respBuffer);
/* send data as message (we already added the CRLF.CRLF) */
event_start(ptcx, &stats->msgwrite);
numBytes = sendMessage(ptcx, ptcx->sock, pish->msgdata);
if (numBytes == -1) {
event_stop(ptcx, &stats->msgwrite);
if (gf_timeexpired < EXIT_FAST) {
returnerr(debugfile, "%s SMTP Error sending mail message: %s\n",
ptcx->errMsg, neterrstr());
stats->msgwrite.errs++;
}
doSMTPExit (ptcx, me);
return -1;
}
/* read server response */
numBytes = readResponse(ptcx, ptcx->sock, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->msgwrite);
if (numBytes <= 0) {
if (gf_timeexpired < EXIT_FAST) {
returnerr(debugfile,"%s SMTP Error reading send message response: %s\n",
ptcx->errMsg, neterrstr());
stats->msgwrite.errs++;
}
doSMTPExit (ptcx, me);
return -1;
}
return 0;
}
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[MAXCOMMANDLEN];
char respBuffer[MAX_RESPONSE_LEN];
int rc;
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
if (BADSOCKET(ptcx->sock)) return; /* closed by previous error */
/* send QUIT */
sprintf(command, "QUIT%s", CRLF);
event_start(ptcx, &stats->logout);
rc = doSmtpCommandResponse(ptcx, ptcx->sock, command, respBuffer, sizeof(respBuffer));
event_stop(ptcx, &stats->logout);
if (rc == -1) {
if (gf_timeexpired < EXIT_FAST) {
stats->logout.errs++;
returnerr(debugfile, "%s SMTP QUIT ERROR, response [%.99s]\n",
ptcx->errMsg, respBuffer);
}
}
doSMTPExit (ptcx, me);
}
void
doSMTPExit (ptcx_t ptcx, doSMTP_state_t *me)
{
if (!BADSOCKET(ptcx->sock))
NETCLOSE(ptcx->sock);
ptcx->sock = BADSOCKET_VALUE;
myfree (me);
}

397
mstone/src/sysdep.c Normal file
Просмотреть файл

@ -0,0 +1,397 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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): Dan Christian <robodan@netscape.com>
* Marcel DePaolis <marcel@netcape.com>
* Mike Blakely
*
* 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"
#ifdef USE_LRAND48_R /* also AIX (only when using threads)*/
struct drand48_data drand48data;
/* should verify that the struct drand48_data can be shared between threads */
void
osf_srand48_r(unsigned int seed)
{
srand48_r(seed, &drand48data);
}
long
osf_lrand48_r(void)
{
long ret;
lrand48_r(&drand48data, &ret);
return ret;
}
#endif /* __OSF1__ */
#ifdef _WIN32
/* close socket library at exit() time */
void sock_cleanup(void) {
WSACleanup();
}
#endif /* _WIN32 */
/* neither sleep or usleep re-start if interrupted */
void
MS_sleep(unsigned int secs)
{
#ifdef _WIN32
Sleep(secs * 1000);
#else
struct timeval sleeptime;
/*D_PRINTF(stderr, "MS_sleep(%d)\n", secs);*/
sleeptime.tv_sec = secs;
sleeptime.tv_usec = 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
}
void
MS_usleep(unsigned int microsecs)
{
#ifdef _WIN32
Sleep(microsecs / 1000);
#else
struct timeval sleeptime;
/*D_PRINTF(stderr, "MS_usleep(%d)\n", microsecs);*/
sleeptime.tv_sec = USECS_2_SECS(microsecs);
sleeptime.tv_usec = microsecs % USECINSEC;
if (select( (int)NULL, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL,
&sleeptime ) < 0) {
D_PRINTF (stderr, "MS_usleep %lu returned early\n", microsecs);
}
#endif
}
/* strerror() */
#ifndef HAVE_STRERROR
/* strerror is not available on SunOS 4.1.3 and others */
extern int sys_nerr;
extern char *sys_errlist[];
extern int errno;
char *strerror(int errnum)
{
if (errnum<sys_nerr) {
return(sys_errlist[errnum]);
}
return(NULL);
}
#endif /* strerror() */
/* stub routines for NT */
#ifdef WIN32
#include <winsock.h>
#include <process.h>
int getpid(void) {
return GetCurrentThreadId();
}
#include <sys/timeb.h> /* For prototype of "_ftime()" */
/*
* gettimeofday() -- gets the current time in elapsed seconds and
* microsends since GMT Jan 1, 1970.
*
* ARGUMENTS: - Pointer to a timeval struct to return the time into
*
* RETURN CODES: - 0 on success
* -1 on failure
*/
int gettimeofday(struct timeval *curTimeP)
{
struct _timeb localTime;
if (curTimeP == (struct timeval *) NULL) {
errno = EFAULT;
return (-1);
}
/*
* Compute the elapsed time since Jan 1, 1970 by first
* obtaining the elapsed time from the system using the
* _ftime(..) call and then convert to the "timeval"
* equivalent.
*/
_ftime(&localTime);
curTimeP->tv_sec = localTime.time;
curTimeP->tv_usec = localTime.millitm * 1000;
return(0);
}
void
crank_limits(void)
{}
void
setup_signal_handlers(void)
{}
int
sysdep_thread_create(THREAD_ID *id, thread_fn_t tfn, void *arg)
{
if (_beginthread(tfn, NT_STACKSIZE, arg) == -1) {
errexit(stderr, "_beginthread failed: %d", GetLastError());
return -1;
}
return 0;
}
int
sysdep_thread_join(THREAD_ID id, int *pstatus)
{
return 0;
}
#else /* !_WIN32 */
#define MAX_TRYFDS (64*1024)
void
crank_limits(void)
{
struct rlimit rlim;
int cur_lim;
int rc;
#ifdef __OSF1__
D_PRINTF(stderr, "attempting to enable support for up to 64k file descriptors\n");
rc = setsysinfo(SSI_FD_NEWMAX, NULL, 0, NULL, 1);
if (rc == -1) {
perror("setsysinfo()");
}
#endif /* __OSF1__ */
D_PRINTF(stderr, "attempting to increase our hard limit (up to %d)\n", MAX_TRYFDS);
rc = getrlimit(RLIMIT_NOFILE, &rlim);
if (rc == -1) {
returnerr(stderr, "getrlimit()");
exit(-1);
}
for (cur_lim = rlim.rlim_max; cur_lim < MAX_TRYFDS; cur_lim += 1024) {
rlim.rlim_max = cur_lim;
rc = setrlimit(RLIMIT_NOFILE, &rlim);
if (rc == -1) {
D_PRINTF (stderr, "setrlimit(RLIMIT_NOFILE, [rlim_max=%d]): errno=%d: %s\n",
rlim.rlim_max, errno, strerror(errno));
break;
}
}
D_PRINTF(stderr, "attempting to increase our soft limit\n");
rc = getrlimit(RLIMIT_NOFILE, &rlim);
if (rc == -1) {
returnerr(stderr, "getrlimit()");
exit(-1);
}
rlim.rlim_cur = rlim.rlim_max;
rc = setrlimit(RLIMIT_NOFILE, &rlim);
if (rc == -1) {
D_PRINTF (stderr, "setrlimit(RLIMIT_NOFILE, [rlim_cur=%d]): errno=%d: %s\n",
rlim.rlim_cur, errno, strerror(errno));
exit(-1);
}
getrlimit(RLIMIT_NOFILE, &rlim);
if (rlim.rlim_cur < 256) { /* show if lower than docs suggest */
returnerr (stderr, "RLIMIT_NOFILE = %d. max processes/threads ~ %d\n",
rlim.rlim_cur, rlim.rlim_cur-10);
} else {
D_PRINTF (stderr, "RLIMIT_NOFILE = %d. max processes/threads ~ %d\n",
rlim.rlim_cur, rlim.rlim_cur-10);
}
}
static void
nullHandler(int sig)
{
/* Dont do anything, (trap SIGPIPE) */
return;
}
static void
alarmHandler(int sig)
{
/* Dont do anything, mainly break system calls */
if (gf_timeexpired < EXIT_SOON) gf_timeexpired = EXIT_SOON;
return;
}
static void
hupHandler(int sig)
{
if (gf_timeexpired < EXIT_SOON) { /* first time, go to clean stop */
beginShutdown ();
} else if (gf_timeexpired < EXIT_FAST) { /* second time, faster */
gf_timeexpired = EXIT_FAST;
} else if (gf_timeexpired < EXIT_FASTEST) { /* second time, fastest */
gf_timeexpired = EXIT_FASTEST;
} else { /* third time, exit */
exit (sig);
}
}
#if 0 /* not used */
/* Received a signal that a child process has exited */
void
childHandler(int sig)
{
int status;
/*D_PRINTF(stderr, "A child process has exited\n" );*/
while (wait3(&status, WNOHANG, (struct rusage *)0) > 0) {
/* do nothing */
/*D_PRINTF(stderr, "wait3() says %d died\n", status);;*/
}
}
#endif
void
setup_signal_handlers(void)
{
/* We will loop until the alarm goes off (should abort system calls). */
#ifdef __LINUX__
{ /* setup signal handler */
struct sigaction sig;
sig.sa_flags = 0;
sig.sa_restorer = 0;
sigemptyset (&sig.sa_mask);
sig.sa_handler = alarmHandler;
sigaction (SIGALRM, &sig, NULL);
sig.sa_handler = hupHandler;
sigaction (SIGHUP, &sig, NULL);
sigaction (SIGTERM, &sig, NULL);
sig.sa_handler = nullHandler;
sigaction (SIGPIPE, &sig, NULL);
}
#else
sigset(SIGALRM, alarmHandler);
sigset(SIGHUP, hupHandler);
sigset(SIGTERM, hupHandler);
sigset(SIGPIPE, nullHandler);
#endif
}
int
sysdep_thread_create(THREAD_ID *id, thread_fn_t tfn, void *arg)
{
#ifdef USE_PTHREADS
int ret;
pthread_attr_t attr;
if ((ret=pthread_attr_init(&attr)) != 0) {
returnerr(stderr, "pthread_attr_init() ret=%d errno=%d: %s\n",
ret, errno, strerror(errno));
return -1;
}
#if 0 /* the default thread attributes */
pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
pthread_attr_setstackaddr(&attr, NULL); /* allocated by system */
pthread_attr_setstacksize(&attr, NULL); /* 1 MB */
pthread_attr_setschedparam(&attr, _PARENT_); /* priority of parent */
pthread_attr_setschedpolicy(&attr, SCHED_OTHER); /* determined by system */
/* also have SCHED_FIFO and SCHED_RR */
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
#endif
#ifdef __AIX__
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
#else
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
#endif
#ifdef THREADS_SCOPE_SYSTEM
/* bound threads, one thread per LWP */
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
#endif
if ((ret=pthread_create(id, &attr, tfn, arg)) != 0) {
returnerr(stderr, "pthread_create() failed ret=%d errno=%d: %s\n",
ret, errno, strerror(errno));
return -1;
}
if ((ret=pthread_attr_destroy(&attr)) != 0) {
returnerr(stderr, "pthread_attr_destroy() ret=%d errno=%d: %s\n",
ret, errno, strerror(errno));
return -1;
}
#endif
return 0;
}
int
sysdep_thread_join(THREAD_ID id, int *pstatus)
{
int ret;
for (;;) {
errno = 0;
*pstatus = 0;
if ((ret = pthread_join(id, (void **)pstatus)) == 0)
break;
D_PRINTF(stderr, "pthread_join(%d) error ret=%d status=%d: errno=%d: %s\n",
id, ret, *pstatus, errno, strerror(errno));
}
return 0;
}
#endif /* WIN32 */

202
mstone/src/sysdep.h Normal file
Просмотреть файл

@ -0,0 +1,202 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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): Dan Christian <robodan@netscape.com>
* Marcel DePaolis <marcel@netcape.com>
* Mike Blakely
* David Shak
*
* 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 __SYSDEP_H__
#define __SYSDEP_H__
/* include config.h, output from autoconf */
#ifdef HAVE_CONFIG_H
#ifndef __CONFIG_H__
#define __CONFIG_H__
/* borrow config.h from gnuplot. Should build our own */
#include "gnuplot/config.h"
#endif
#else
/* Modern OSes have these */
#define HAVE_SNPRINTF 1
#define HAVE_STRERROR 1
#endif
#ifdef _WIN32
#include <windows.h>
#include <winsock.h>
#else
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#endif /* _WIN32 */
#ifdef __OSF1__
#include <sys/sysinfo.h> /* for setsysinfo() */
#endif
/* MAXHOSTNAMELEN is undefined on some systems */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
/* SunOS doesn't define NULL */
#ifndef NULL
#define NULL 0
#endif
/* 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 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 S_ADDR S_un.S_addr
#define GET_ERROR WSAGetLastError()
#define SET_ERROR(err) WSASetLastError(err)
/* NT gettimeofday() doesn't support USE_TIMEZONE (yet) */
#include <time.h>
#define GETTIMEOFDAY(timeval, tz) gettimeofday(timeval)
typedef unsigned short NETPORT;
#define SRANDOM srand
#define RANDOM rand
#define PROGPATH "c:\\mailstone\\mailclient"
#define FILENAME_SIZE 256
#define HAVE_VPRINTF 1
#define SIGCHLD 0 /* dummy value */
#define SIGALRM 0 /* dummy value */
typedef int pid_t;
typedef unsigned short ushort;
#define MAXPATHLEN 512
extern void sock_cleanup(void);
#define THREAD_RET void
#define THREAD_ID int
#else /* not _WIN32 */
#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 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 S_ADDR s_addr
#define GET_ERROR errno
#define SET_ERROR(err) (errno = (err))
#define GETTIMEOFDAY(timeval,tz) gettimeofday(timeval, NULL)
typedef unsigned short NETPORT;
#if defined (USE_LRAND48_R)
extern void osf_srand48_r(unsigned int seed);
extern long osf_lrand48_r(void);
#define SRANDOM osf_srand48_r
#define RANDOM osf_lrand48_r
#elif defined (USE_LRAND48)
#define SRANDOM srand48
#define RANDOM lrand48
#else /* !USE_LRAND48 */
#define SRANDOM srandom
#define RANDOM random
#endif /* USE_LRAND48_R */
#define PROGPATH "/mailstone/mailclient"
#define FILENAME_SIZE 1024
#define HAVE_VPRINTF 1
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
#define THREAD_ID pthread_t
#else
#define THREAD_ID int
#endif
#endif /* _WIN32 */
typedef THREAD_RET (*thread_fn_t)(void *);
/* function prototypes */
extern void crank_limits(void);
extern int sysdep_thread_create(THREAD_ID *id, thread_fn_t tfn, void *arg);
extern int sysdep_thread_join(THREAD_ID id, int *pstatus);
extern void setup_signal_handlers (void);
#ifdef _WIN32
int getopt(int argc, char ** argv, char *opts);
int getpid(void);
int gettimeofday(struct timeval *curTimeP);
int random_number(int max);
SOCKET rexec(const char **hostname, NETPORT port, char *username, char *password,
char *command, SOCKET *sockerr);
#else
#ifdef NO_REXEC
extern int rexec(char **, int, char *, char *, char *, int *);
#endif
#endif /* _WIN32 */
#ifndef HAVE_STRERROR
/* strerror() is not available on SunOS 4.x and others */
char *strerror(int errnum);
#endif
/* strerror() */
#ifndef INADDR_NONE
#define INADDR_NONE -1
#endif
#endif /* !__SYSDEP_H__ */

73
mstone/src/timefunc.c Normal file
Просмотреть файл

@ -0,0 +1,73 @@
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 40 -*- */
/*
* 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): Dan Christian <robodan@netscape.com>
* Marcel DePaolis <marcel@netcape.com>
* Mike Blakely
*
* 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.
*/
/*
Stuff that deals with timevals.
*/
#include "bench.h"
double
timevaldouble(struct timeval *tin)
{
return ((double)tin->tv_sec + ((double)tin->tv_usec / USECINSEC));
}
void
doubletimeval(const double tin, struct timeval *tout)
{
tout->tv_sec = (long)floor(tin);
tout->tv_usec = (long)((tin - tout->tv_sec) * USECINSEC );
}
/* Difference two timevals and return as a double (in seconds) */
/* Could be a macro */
double
compdifftime_double(struct timeval *EndTime, struct timeval *StartTime)
{
/* doing the integeger differences first is supposed to prevent
any loss in resolution (more important if we returned float instead) */
double d = (EndTime->tv_sec - StartTime->tv_sec)
+ ((double)(EndTime->tv_usec - StartTime->tv_usec)*(1.0/USECINSEC));
if (d < 0.0) {
D_PRINTF (stderr, "Woa! compdifftime negative start %lu.%06lu end %lu.%06lu\n",
StartTime->tv_sec, StartTime->tv_usec,
EndTime->tv_sec, EndTime->tv_usec);
return 0.0;
}
return d;
}

1382
mstone/src/wmap.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу