зеркало из https://github.com/mozilla/pjs.git
Initial open source checkin of the mstone performance tool
This commit is contained in:
Родитель
e3a117d3c9
Коммит
368d4c9e07
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
||||
|
|
@ -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
|
|
@ -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".
|
|
@ -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,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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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> </TD><TD> </TD><TD> </TD><TD> </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;
|
|
@ -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,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;
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
|
@ -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,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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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,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>
|
|
@ -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,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
|
||||
#
|
||||
########################################################################
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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,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,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,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,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, µseconds);
|
||||
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
|
|
@ -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__ */
|
|
@ -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(¤tTime);
|
||||
tmptm = localtime(¤tTime);
|
||||
strftime(timeStamp, DATESTAMP_LEN, "%Y%m%d%H%M%S", tmptm);
|
||||
D_PRINTF(debugfile, "Time Stamp: %s\n", timeStamp);
|
||||
D_PRINTF(debugfile, "mailstone run dateStamp=%s\n", gs_dateStamp);
|
||||
}
|
||||
|
||||
#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(¤tTime);
|
||||
tmptm = localtime(¤tTime);
|
||||
strftime(timeStamp, DATESTAMP_LEN, "%Y%m%d%H%M%S", tmptm);
|
||||
D_PRINTF(debugfile, "Time Stamp: %s\n", timeStamp);
|
||||
|
||||
if (gn_record_telemetry && (ptcx->logfile > 0)) {
|
||||
close(ptcx->logfile);
|
||||
ptcx->logfile = -1;
|
||||
}
|
||||
|
||||
D_PRINTF(debugfile, "client exiting.\n" );
|
||||
|
||||
if (gn_debug && ptcx->dfile) {
|
||||
fflush(ptcx->dfile);
|
||||
if (ptcx->dfile != stderr) {
|
||||
fclose(ptcx->dfile);
|
||||
ptcx->dfile = stderr;
|
||||
}
|
||||
}
|
||||
|
||||
/*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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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(¤tTime);
|
||||
tmptm = localtime(¤tTime);
|
||||
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() */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче