michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nspr.h" michael@0: michael@0: #include "plgetopt.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: michael@0: #ifndef IOV_MAX michael@0: #define IOV_MAX 16 michael@0: #endif michael@0: michael@0: #define BASE_PORT 9867 michael@0: michael@0: int PR_CALLBACK Writev(int argc, char **argv) michael@0: { michael@0: michael@0: PRStatus rv; michael@0: PRNetAddr serverAddr; michael@0: PRFileDesc *clientSock, *debug = NULL; michael@0: michael@0: char *buffer = NULL; michael@0: PRIOVec *iov = NULL; michael@0: PRBool passed = PR_TRUE; michael@0: PRIntervalTime timein, elapsed, timeout; michael@0: PRIntervalTime tmo_min = 0x7fffffff, tmo_max = 0, tmo_elapsed = 0; michael@0: PRInt32 tmo_counted = 0, iov_index, loop, bytes, number_fragments; michael@0: PRInt32 message_length = 100, fragment_length = 100, messages = 100; michael@0: struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; michael@0: michael@0: /* michael@0: * USAGE michael@0: * -h dns name of host serving the connection (default = self) michael@0: * -m number of messages to send (default = 100) michael@0: * -s size of each message (default = 100) michael@0: * -f size of each message fragment (default = 100) michael@0: */ michael@0: michael@0: PLOptStatus os; michael@0: PLOptState *opt = PL_CreateOptState(argc, argv, "dh:m:s:f:"); michael@0: michael@0: PR_STDIO_INIT(); michael@0: rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddr); michael@0: PR_ASSERT(PR_SUCCESS == rv); michael@0: michael@0: while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) michael@0: { michael@0: if (PL_OPT_BAD == os) continue; michael@0: switch (opt->option) michael@0: { michael@0: case 'h': /* the remote host */ michael@0: { michael@0: PRIntn es = 0; michael@0: PRHostEnt host; michael@0: char buffer[1024]; michael@0: (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host); michael@0: es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &serverAddr); michael@0: PR_ASSERT(es > 0); michael@0: } michael@0: break; michael@0: case 'd': /* debug mode */ michael@0: debug = PR_GetSpecialFD(PR_StandardError); michael@0: break; michael@0: case 'm': /* number of messages to send */ michael@0: messages = atoi(opt->value); michael@0: break; michael@0: case 's': /* total size of each message */ michael@0: message_length = atoi(opt->value); michael@0: break; michael@0: case 'f': /* size of each message fragment */ michael@0: fragment_length = atoi(opt->value); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: PL_DestroyOptState(opt); michael@0: michael@0: buffer = (char*)malloc(message_length); michael@0: michael@0: number_fragments = (message_length + fragment_length - 1) / fragment_length + 1; michael@0: while (IOV_MAX < number_fragments) michael@0: { michael@0: fragment_length = message_length / (IOV_MAX - 2); michael@0: number_fragments = (message_length + fragment_length - 1) / michael@0: fragment_length + 1; michael@0: if (NULL != debug) PR_fprintf(debug, michael@0: "Too many fragments - reset fragment length to %ld\n", fragment_length); michael@0: } michael@0: iov = (PRIOVec*)malloc(number_fragments * sizeof(PRIOVec)); michael@0: michael@0: iov[0].iov_base = (char*)&descriptor; michael@0: iov[0].iov_len = sizeof(descriptor); michael@0: for (iov_index = 1; iov_index < number_fragments; ++iov_index) michael@0: { michael@0: iov[iov_index].iov_base = buffer + (iov_index - 1) * fragment_length; michael@0: iov[iov_index].iov_len = fragment_length; michael@0: } michael@0: michael@0: for (bytes = 0; bytes < message_length; ++bytes) michael@0: buffer[bytes] = (char)bytes; michael@0: michael@0: timeout = PR_SecondsToInterval(1); michael@0: michael@0: for (loop = 0; loop < messages; ++loop) michael@0: { michael@0: if (NULL != debug) michael@0: PR_fprintf(debug, "[%d]socket ... ", loop); michael@0: clientSock = PR_NewTCPSocket(); michael@0: if (clientSock) michael@0: { michael@0: timein = PR_IntervalNow(); michael@0: if (NULL != debug) michael@0: PR_fprintf(debug, "connecting ... "); michael@0: rv = PR_Connect(clientSock, &serverAddr, timeout); michael@0: if (PR_SUCCESS == rv) michael@0: { michael@0: descriptor.checksum = 0; michael@0: descriptor.length = (loop < (messages - 1)) ? message_length : 0; michael@0: if (0 == descriptor.length) number_fragments = 1; michael@0: else michael@0: for (iov_index = 0; iov_index < descriptor.length; ++iov_index) michael@0: { michael@0: PRUint32 overflow = descriptor.checksum & 0x80000000; michael@0: descriptor.checksum = (descriptor.checksum << 1); michael@0: if (0x00000000 != overflow) descriptor.checksum += 1; michael@0: descriptor.checksum += buffer[iov_index]; michael@0: } michael@0: if (NULL != debug) PR_fprintf( michael@0: debug, "sending %d bytes ... ", descriptor.length); michael@0: michael@0: /* then, at the last moment ... */ michael@0: descriptor.length = PR_ntohl(descriptor.length); michael@0: descriptor.checksum = PR_ntohl(descriptor.checksum); michael@0: michael@0: bytes = PR_Writev(clientSock, iov, number_fragments, timeout); michael@0: if (NULL != debug) michael@0: PR_fprintf(debug, "closing ... "); michael@0: rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); michael@0: rv = PR_Close(clientSock); michael@0: if (NULL != debug) PR_fprintf( michael@0: debug, "%s\n", ((PR_SUCCESS == rv) ? "good" : "bad")); michael@0: elapsed = PR_IntervalNow() - timein; michael@0: if (elapsed < tmo_min) tmo_min = elapsed; michael@0: else if (elapsed > tmo_max) tmo_max = elapsed; michael@0: tmo_elapsed += elapsed; michael@0: tmo_counted += 1; michael@0: } michael@0: else michael@0: { michael@0: if (NULL != debug) PR_fprintf( michael@0: debug, "failed - retrying (%d, %d)\n", michael@0: PR_GetError(), PR_GetOSError()); michael@0: PR_Close(clientSock); michael@0: } michael@0: } michael@0: else if (NULL != debug) michael@0: { michael@0: PR_fprintf(debug, "unable to create client socket\n"); michael@0: passed = PR_FALSE; michael@0: } michael@0: } michael@0: if (NULL != debug) { michael@0: if (0 == tmo_counted) { michael@0: PR_fprintf(debug, "No connection made\n"); michael@0: } else { michael@0: PR_fprintf( michael@0: debug, "\nTimings: %d [%d] %d (microseconds)\n", michael@0: PR_IntervalToMicroseconds(tmo_min), michael@0: PR_IntervalToMicroseconds(tmo_elapsed / tmo_counted), michael@0: PR_IntervalToMicroseconds(tmo_max)); michael@0: } michael@0: } michael@0: michael@0: PR_DELETE(buffer); michael@0: PR_DELETE(iov); michael@0: michael@0: PR_fprintf( michael@0: PR_GetSpecialFD(PR_StandardError), michael@0: "%s\n", (passed) ? "PASSED" : "FAILED"); michael@0: return (passed) ? 0 : 1; michael@0: } michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: return (PR_VersionCheck(PR_VERSION)) ? michael@0: PR_Initialize(Writev, argc, argv, 4) : -1; michael@0: } /* main */ michael@0: michael@0: /* writev.c */ michael@0: michael@0: