1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/writev.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,197 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nspr.h" 1.10 + 1.11 +#include "plgetopt.h" 1.12 + 1.13 +#include <stdlib.h> 1.14 +#include <string.h> 1.15 + 1.16 + 1.17 +#ifndef IOV_MAX 1.18 +#define IOV_MAX 16 1.19 +#endif 1.20 + 1.21 +#define BASE_PORT 9867 1.22 + 1.23 +int PR_CALLBACK Writev(int argc, char **argv) 1.24 +{ 1.25 + 1.26 + PRStatus rv; 1.27 + PRNetAddr serverAddr; 1.28 + PRFileDesc *clientSock, *debug = NULL; 1.29 + 1.30 + char *buffer = NULL; 1.31 + PRIOVec *iov = NULL; 1.32 + PRBool passed = PR_TRUE; 1.33 + PRIntervalTime timein, elapsed, timeout; 1.34 + PRIntervalTime tmo_min = 0x7fffffff, tmo_max = 0, tmo_elapsed = 0; 1.35 + PRInt32 tmo_counted = 0, iov_index, loop, bytes, number_fragments; 1.36 + PRInt32 message_length = 100, fragment_length = 100, messages = 100; 1.37 + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; 1.38 + 1.39 + /* 1.40 + * USAGE 1.41 + * -h dns name of host serving the connection (default = self) 1.42 + * -m number of messages to send (default = 100) 1.43 + * -s size of each message (default = 100) 1.44 + * -f size of each message fragment (default = 100) 1.45 + */ 1.46 + 1.47 + PLOptStatus os; 1.48 + PLOptState *opt = PL_CreateOptState(argc, argv, "dh:m:s:f:"); 1.49 + 1.50 + PR_STDIO_INIT(); 1.51 + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddr); 1.52 + PR_ASSERT(PR_SUCCESS == rv); 1.53 + 1.54 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.55 + { 1.56 + if (PL_OPT_BAD == os) continue; 1.57 + switch (opt->option) 1.58 + { 1.59 + case 'h': /* the remote host */ 1.60 + { 1.61 + PRIntn es = 0; 1.62 + PRHostEnt host; 1.63 + char buffer[1024]; 1.64 + (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host); 1.65 + es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &serverAddr); 1.66 + PR_ASSERT(es > 0); 1.67 + } 1.68 + break; 1.69 + case 'd': /* debug mode */ 1.70 + debug = PR_GetSpecialFD(PR_StandardError); 1.71 + break; 1.72 + case 'm': /* number of messages to send */ 1.73 + messages = atoi(opt->value); 1.74 + break; 1.75 + case 's': /* total size of each message */ 1.76 + message_length = atoi(opt->value); 1.77 + break; 1.78 + case 'f': /* size of each message fragment */ 1.79 + fragment_length = atoi(opt->value); 1.80 + break; 1.81 + default: 1.82 + break; 1.83 + } 1.84 + } 1.85 + PL_DestroyOptState(opt); 1.86 + 1.87 + buffer = (char*)malloc(message_length); 1.88 + 1.89 + number_fragments = (message_length + fragment_length - 1) / fragment_length + 1; 1.90 + while (IOV_MAX < number_fragments) 1.91 + { 1.92 + fragment_length = message_length / (IOV_MAX - 2); 1.93 + number_fragments = (message_length + fragment_length - 1) / 1.94 + fragment_length + 1; 1.95 + if (NULL != debug) PR_fprintf(debug, 1.96 + "Too many fragments - reset fragment length to %ld\n", fragment_length); 1.97 + } 1.98 + iov = (PRIOVec*)malloc(number_fragments * sizeof(PRIOVec)); 1.99 + 1.100 + iov[0].iov_base = (char*)&descriptor; 1.101 + iov[0].iov_len = sizeof(descriptor); 1.102 + for (iov_index = 1; iov_index < number_fragments; ++iov_index) 1.103 + { 1.104 + iov[iov_index].iov_base = buffer + (iov_index - 1) * fragment_length; 1.105 + iov[iov_index].iov_len = fragment_length; 1.106 + } 1.107 + 1.108 + for (bytes = 0; bytes < message_length; ++bytes) 1.109 + buffer[bytes] = (char)bytes; 1.110 + 1.111 + timeout = PR_SecondsToInterval(1); 1.112 + 1.113 + for (loop = 0; loop < messages; ++loop) 1.114 + { 1.115 + if (NULL != debug) 1.116 + PR_fprintf(debug, "[%d]socket ... ", loop); 1.117 + clientSock = PR_NewTCPSocket(); 1.118 + if (clientSock) 1.119 + { 1.120 + timein = PR_IntervalNow(); 1.121 + if (NULL != debug) 1.122 + PR_fprintf(debug, "connecting ... "); 1.123 + rv = PR_Connect(clientSock, &serverAddr, timeout); 1.124 + if (PR_SUCCESS == rv) 1.125 + { 1.126 + descriptor.checksum = 0; 1.127 + descriptor.length = (loop < (messages - 1)) ? message_length : 0; 1.128 + if (0 == descriptor.length) number_fragments = 1; 1.129 + else 1.130 + for (iov_index = 0; iov_index < descriptor.length; ++iov_index) 1.131 + { 1.132 + PRUint32 overflow = descriptor.checksum & 0x80000000; 1.133 + descriptor.checksum = (descriptor.checksum << 1); 1.134 + if (0x00000000 != overflow) descriptor.checksum += 1; 1.135 + descriptor.checksum += buffer[iov_index]; 1.136 + } 1.137 + if (NULL != debug) PR_fprintf( 1.138 + debug, "sending %d bytes ... ", descriptor.length); 1.139 + 1.140 + /* then, at the last moment ... */ 1.141 + descriptor.length = PR_ntohl(descriptor.length); 1.142 + descriptor.checksum = PR_ntohl(descriptor.checksum); 1.143 + 1.144 + bytes = PR_Writev(clientSock, iov, number_fragments, timeout); 1.145 + if (NULL != debug) 1.146 + PR_fprintf(debug, "closing ... "); 1.147 + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); 1.148 + rv = PR_Close(clientSock); 1.149 + if (NULL != debug) PR_fprintf( 1.150 + debug, "%s\n", ((PR_SUCCESS == rv) ? "good" : "bad")); 1.151 + elapsed = PR_IntervalNow() - timein; 1.152 + if (elapsed < tmo_min) tmo_min = elapsed; 1.153 + else if (elapsed > tmo_max) tmo_max = elapsed; 1.154 + tmo_elapsed += elapsed; 1.155 + tmo_counted += 1; 1.156 + } 1.157 + else 1.158 + { 1.159 + if (NULL != debug) PR_fprintf( 1.160 + debug, "failed - retrying (%d, %d)\n", 1.161 + PR_GetError(), PR_GetOSError()); 1.162 + PR_Close(clientSock); 1.163 + } 1.164 + } 1.165 + else if (NULL != debug) 1.166 + { 1.167 + PR_fprintf(debug, "unable to create client socket\n"); 1.168 + passed = PR_FALSE; 1.169 + } 1.170 + } 1.171 + if (NULL != debug) { 1.172 + if (0 == tmo_counted) { 1.173 + PR_fprintf(debug, "No connection made\n"); 1.174 + } else { 1.175 + PR_fprintf( 1.176 + debug, "\nTimings: %d [%d] %d (microseconds)\n", 1.177 + PR_IntervalToMicroseconds(tmo_min), 1.178 + PR_IntervalToMicroseconds(tmo_elapsed / tmo_counted), 1.179 + PR_IntervalToMicroseconds(tmo_max)); 1.180 + } 1.181 + } 1.182 + 1.183 + PR_DELETE(buffer); 1.184 + PR_DELETE(iov); 1.185 + 1.186 + PR_fprintf( 1.187 + PR_GetSpecialFD(PR_StandardError), 1.188 + "%s\n", (passed) ? "PASSED" : "FAILED"); 1.189 + return (passed) ? 0 : 1; 1.190 +} 1.191 + 1.192 +int main(int argc, char **argv) 1.193 +{ 1.194 + return (PR_VersionCheck(PR_VERSION)) ? 1.195 + PR_Initialize(Writev, argc, argv, 4) : -1; 1.196 +} /* main */ 1.197 + 1.198 +/* writev.c */ 1.199 + 1.200 +