1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
---|
2 | /* ***** BEGIN LICENSE BLOCK *****
|
---|
3 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
---|
4 | *
|
---|
5 | * The contents of this file are subject to the Mozilla Public License Version
|
---|
6 | * 1.1 (the "License"); you may not use this file except in compliance with
|
---|
7 | * the License. You may obtain a copy of the License at
|
---|
8 | * http://www.mozilla.org/MPL/
|
---|
9 | *
|
---|
10 | * Software distributed under the License is distributed on an "AS IS" basis,
|
---|
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
---|
12 | * for the specific language governing rights and limitations under the
|
---|
13 | * License.
|
---|
14 | *
|
---|
15 | * The Original Code is the Netscape Portable Runtime (NSPR).
|
---|
16 | *
|
---|
17 | * The Initial Developer of the Original Code is
|
---|
18 | * Netscape Communications Corporation.
|
---|
19 | * Portions created by the Initial Developer are Copyright (C) 1998-2000
|
---|
20 | * the Initial Developer. All Rights Reserved.
|
---|
21 | *
|
---|
22 | * Contributor(s):
|
---|
23 | *
|
---|
24 | * Alternatively, the contents of this file may be used under the terms of
|
---|
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
|
---|
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
---|
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
|
---|
28 | * of those above. If you wish to allow use of your version of this file only
|
---|
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
|
---|
30 | * use your version of this file under the terms of the MPL, indicate your
|
---|
31 | * decision by deleting the provisions above and replace them with the notice
|
---|
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
|
---|
33 | * the provisions above, a recipient may use your version of this file under
|
---|
34 | * the terms of any one of the MPL, the GPL or the LGPL.
|
---|
35 | *
|
---|
36 | * ***** END LICENSE BLOCK ***** */
|
---|
37 |
|
---|
38 | #include "nspr.h"
|
---|
39 |
|
---|
40 | #include "plgetopt.h"
|
---|
41 |
|
---|
42 | #include <stdlib.h>
|
---|
43 | #include <string.h>
|
---|
44 |
|
---|
45 | #ifdef XP_MAC
|
---|
46 | #include "prlog.h"
|
---|
47 | #define printf PR_LogPrint
|
---|
48 | #endif
|
---|
49 |
|
---|
50 |
|
---|
51 | #ifndef IOV_MAX
|
---|
52 | #define IOV_MAX 16
|
---|
53 | #endif
|
---|
54 |
|
---|
55 | #define BASE_PORT 9867
|
---|
56 |
|
---|
57 | int PR_CALLBACK Writev(int argc, char **argv)
|
---|
58 | {
|
---|
59 |
|
---|
60 | PRStatus rv;
|
---|
61 | PRNetAddr serverAddr;
|
---|
62 | PRFileDesc *clientSock, *debug = NULL;
|
---|
63 |
|
---|
64 | char *buffer = NULL;
|
---|
65 | PRIOVec *iov = NULL;
|
---|
66 | PRBool passed = PR_TRUE;
|
---|
67 | PRIntervalTime timein, elapsed, timeout;
|
---|
68 | PRIntervalTime tmo_min = 0x7fffffff, tmo_max = 0, tmo_elapsed = 0;
|
---|
69 | PRInt32 tmo_counted = 0, iov_index, loop, bytes, number_fragments;
|
---|
70 | PRInt32 message_length = 100, fragment_length = 100, messages = 100;
|
---|
71 | struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor;
|
---|
72 |
|
---|
73 | /*
|
---|
74 | * USAGE
|
---|
75 | * -h dns name of host serving the connection (default = self)
|
---|
76 | * -m number of messages to send (default = 100)
|
---|
77 | * -s size of each message (default = 100)
|
---|
78 | * -f size of each message fragment (default = 100)
|
---|
79 | */
|
---|
80 |
|
---|
81 | PLOptStatus os;
|
---|
82 | PLOptState *opt = PL_CreateOptState(argc, argv, "dh:m:s:f:");
|
---|
83 |
|
---|
84 | PR_STDIO_INIT();
|
---|
85 | rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddr);
|
---|
86 | PR_ASSERT(PR_SUCCESS == rv);
|
---|
87 |
|
---|
88 | while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
|
---|
89 | {
|
---|
90 | if (PL_OPT_BAD == os) continue;
|
---|
91 | switch (opt->option)
|
---|
92 | {
|
---|
93 | case 'h': /* the remote host */
|
---|
94 | {
|
---|
95 | PRIntn es = 0;
|
---|
96 | PRHostEnt host;
|
---|
97 | char buffer[1024];
|
---|
98 | (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host);
|
---|
99 | es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &serverAddr);
|
---|
100 | PR_ASSERT(es > 0);
|
---|
101 | }
|
---|
102 | break;
|
---|
103 | case 'd': /* debug mode */
|
---|
104 | debug = PR_GetSpecialFD(PR_StandardError);
|
---|
105 | break;
|
---|
106 | case 'm': /* number of messages to send */
|
---|
107 | messages = atoi(opt->value);
|
---|
108 | break;
|
---|
109 | case 's': /* total size of each message */
|
---|
110 | message_length = atoi(opt->value);
|
---|
111 | break;
|
---|
112 | case 'f': /* size of each message fragment */
|
---|
113 | fragment_length = atoi(opt->value);
|
---|
114 | break;
|
---|
115 | default:
|
---|
116 | break;
|
---|
117 | }
|
---|
118 | }
|
---|
119 | PL_DestroyOptState(opt);
|
---|
120 |
|
---|
121 | buffer = (char*)malloc(message_length);
|
---|
122 |
|
---|
123 | number_fragments = (message_length + fragment_length - 1) / fragment_length + 1;
|
---|
124 | while (IOV_MAX < number_fragments)
|
---|
125 | {
|
---|
126 | fragment_length = message_length / (IOV_MAX - 2);
|
---|
127 | number_fragments = (message_length + fragment_length - 1) /
|
---|
128 | fragment_length + 1;
|
---|
129 | if (NULL != debug) PR_fprintf(debug,
|
---|
130 | "Too many fragments - reset fragment length to %ld\n", fragment_length);
|
---|
131 | }
|
---|
132 | iov = (PRIOVec*)malloc(number_fragments * sizeof(PRIOVec));
|
---|
133 |
|
---|
134 | iov[0].iov_base = (char*)&descriptor;
|
---|
135 | iov[0].iov_len = sizeof(descriptor);
|
---|
136 | for (iov_index = 1; iov_index < number_fragments; ++iov_index)
|
---|
137 | {
|
---|
138 | iov[iov_index].iov_base = buffer + (iov_index - 1) * fragment_length;
|
---|
139 | iov[iov_index].iov_len = fragment_length;
|
---|
140 | }
|
---|
141 |
|
---|
142 | for (bytes = 0; bytes < message_length; ++bytes)
|
---|
143 | buffer[bytes] = (char)bytes;
|
---|
144 |
|
---|
145 | timeout = PR_SecondsToInterval(1);
|
---|
146 |
|
---|
147 | for (loop = 0; loop < messages; ++loop)
|
---|
148 | {
|
---|
149 | if (NULL != debug)
|
---|
150 | PR_fprintf(debug, "[%d]socket ... ", loop);
|
---|
151 | clientSock = PR_NewTCPSocket();
|
---|
152 | if (clientSock)
|
---|
153 | {
|
---|
154 | timein = PR_IntervalNow();
|
---|
155 | if (NULL != debug)
|
---|
156 | PR_fprintf(debug, "connecting ... ");
|
---|
157 | rv = PR_Connect(clientSock, &serverAddr, timeout);
|
---|
158 | if (PR_SUCCESS == rv)
|
---|
159 | {
|
---|
160 | descriptor.checksum = 0;
|
---|
161 | descriptor.length = (loop < (messages - 1)) ? message_length : 0;
|
---|
162 | if (0 == descriptor.length) number_fragments = 1;
|
---|
163 | else
|
---|
164 | for (iov_index = 0; iov_index < descriptor.length; ++iov_index)
|
---|
165 | {
|
---|
166 | PRUint32 overflow = descriptor.checksum & 0x80000000;
|
---|
167 | descriptor.checksum = (descriptor.checksum << 1);
|
---|
168 | if (0x00000000 != overflow) descriptor.checksum += 1;
|
---|
169 | descriptor.checksum += buffer[iov_index];
|
---|
170 | }
|
---|
171 | if (NULL != debug) PR_fprintf(
|
---|
172 | debug, "sending %d bytes ... ", descriptor.length);
|
---|
173 |
|
---|
174 | /* then, at the last moment ... */
|
---|
175 | descriptor.length = PR_ntohl(descriptor.length);
|
---|
176 | descriptor.checksum = PR_ntohl(descriptor.checksum);
|
---|
177 |
|
---|
178 | bytes = PR_Writev(clientSock, iov, number_fragments, timeout);
|
---|
179 | if (NULL != debug)
|
---|
180 | PR_fprintf(debug, "closing ... ");
|
---|
181 | rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
|
---|
182 | rv = PR_Close(clientSock);
|
---|
183 | if (NULL != debug) PR_fprintf(
|
---|
184 | debug, "%s\n", ((PR_SUCCESS == rv) ? "good" : "bad"));
|
---|
185 | elapsed = PR_IntervalNow() - timein;
|
---|
186 | if (elapsed < tmo_min) tmo_min = elapsed;
|
---|
187 | else if (elapsed > tmo_max) tmo_max = elapsed;
|
---|
188 | tmo_elapsed += elapsed;
|
---|
189 | tmo_counted += 1;
|
---|
190 | }
|
---|
191 | else
|
---|
192 | {
|
---|
193 | if (NULL != debug) PR_fprintf(
|
---|
194 | debug, "failed - retrying (%d, %d)\n",
|
---|
195 | PR_GetError(), PR_GetOSError());
|
---|
196 | PR_Close(clientSock);
|
---|
197 | }
|
---|
198 | }
|
---|
199 | else if (NULL != debug)
|
---|
200 | {
|
---|
201 | PR_fprintf(debug, "unable to create client socket\n");
|
---|
202 | passed = PR_FALSE;
|
---|
203 | }
|
---|
204 | }
|
---|
205 | if (NULL != debug) {
|
---|
206 | if (0 == tmo_counted) {
|
---|
207 | PR_fprintf(debug, "No connection made\n");
|
---|
208 | } else {
|
---|
209 | PR_fprintf(
|
---|
210 | debug, "\nTimings: %d [%d] %d (microseconds)\n",
|
---|
211 | PR_IntervalToMicroseconds(tmo_min),
|
---|
212 | PR_IntervalToMicroseconds(tmo_elapsed / tmo_counted),
|
---|
213 | PR_IntervalToMicroseconds(tmo_max));
|
---|
214 | }
|
---|
215 | }
|
---|
216 |
|
---|
217 | PR_DELETE(buffer);
|
---|
218 | PR_DELETE(iov);
|
---|
219 |
|
---|
220 | PR_fprintf(
|
---|
221 | PR_GetSpecialFD(PR_StandardError),
|
---|
222 | "%s\n", (passed) ? "PASSED" : "FAILED");
|
---|
223 | return (passed) ? 0 : 1;
|
---|
224 | }
|
---|
225 |
|
---|
226 | int main(int argc, char **argv)
|
---|
227 | {
|
---|
228 | return (PR_VersionCheck(PR_VERSION)) ?
|
---|
229 | PR_Initialize(Writev, argc, argv, 4) : -1;
|
---|
230 | } /* main */
|
---|
231 |
|
---|
232 | /* writev.c */
|
---|
233 |
|
---|
234 |
|
---|