📄 provider.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * The contents of this file are subject to the Mozilla 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/MPL/ * * 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 Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * 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 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 MPL, * 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 MPL or the * GPL. *//* * * Notes: * [1] lth. The call to Sleep() is a hack to get the test case to run * on Windows 95. Without it, the test case fails with an error * WSAECONNRESET following a recv() call. The error is caused by the * server side thread termination without a shutdown() or closesocket() * call. Windows docmunentation suggests that this is predicted * behavior; that other platforms get away with it is ... serindipity. * The test case should shutdown() or closesocket() before * thread termination. I didn't have time to figure out where or how * to do it. The Sleep() call inserts enough delay to allow the * client side to recv() all his data before the server side thread * terminates. Whew! ... * ** Modification History: * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. * The debug mode will print all of the printfs associated with this test. * The regress mode will be the default mode. Since the regress tool limits * the output to a one line status:PASS or FAIL,all of the printf statements * have been handled with an if (debug_mode) statement. */#include "prclist.h"#include "prcvar.h"#include "prerror.h"#include "prinit.h"#include "prinrval.h"#include "prio.h"#include "prlock.h"#include "prlog.h"#include "prtime.h"#include "prmem.h"#include "prnetdb.h"#include "prprf.h"#include "prthread.h"#include "pprio.h"#include "primpl.h"#include "plstr.h"#include "plerror.h"#include "plgetopt.h"#include <stdlib.h>#include <string.h>#if defined(XP_UNIX)#include <math.h>#endif#ifdef XP_MAC#include "prlog.h"#define printf PR_LogPrint#endif/*** This is the beginning of the test*/#define RECV_FLAGS 0#define SEND_FLAGS 0#define BUFFER_SIZE 1024#define DEFAULT_BACKLOG 5#define DEFAULT_PORT 13000#define DEFAULT_CLIENTS 1#define ALLOWED_IN_ACCEPT 1#define DEFAULT_CLIPPING 1000#define DEFAULT_WORKERS_MIN 1#define DEFAULT_WORKERS_MAX 1#define DEFAULT_SERVER "localhost"#define DEFAULT_EXECUTION_TIME 10#define DEFAULT_CLIENT_TIMEOUT 4000#define DEFAULT_SERVER_TIMEOUT 4000#define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGHtypedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t;static void PR_CALLBACK Worker(void *arg);typedef struct CSPool_s CSPool_t;typedef struct CSWorker_s CSWorker_t;typedef struct CSServer_s CSServer_t;typedef enum Verbosity{ TEST_LOG_ALWAYS, TEST_LOG_ERROR, TEST_LOG_WARNING, TEST_LOG_NOTICE, TEST_LOG_INFO, TEST_LOG_STATUS, TEST_LOG_VERBOSE} Verbosity;static enum { thread_nspr, thread_pthread, thread_sproc, thread_win32} thread_provider;static PRInt32 domain = AF_INET;static PRInt32 protocol = 6; /* TCP */static PRFileDesc *debug_out = NULL;static PRBool debug_mode = PR_FALSE;static PRBool pthread_stats = PR_FALSE;static Verbosity verbosity = TEST_LOG_ALWAYS;static PRThreadScope thread_scope = PR_LOCAL_THREAD;struct CSWorker_s{ PRCList element; /* list of the server's workers */ PRThread *thread; /* this worker objects thread */ CSServer_t *server; /* back pointer to server structure */};struct CSPool_s{ PRCondVar *exiting; PRCondVar *acceptComplete; PRUint32 accepting, active, workers;};struct CSServer_s{ PRCList list; /* head of worker list */ PRLock *ml; PRThread *thread; /* the main server thread */ PRCondVar *stateChange; PRUint16 port; /* port we're listening on */ PRUint32 backlog; /* size of our listener backlog */ PRFileDesc *listener; /* the fd accepting connections */ CSPool_t pool; /* statistics on worker threads */ CSState_t state; /* the server's state */ struct /* controlling worker counts */ { PRUint32 minimum, maximum, accepting; } workers; /* statistics */ PRIntervalTime started, stopped; PRUint32 operations, bytesTransferred;};typedef struct CSDescriptor_s{ PRInt32 size; /* size of transfer */ char filename[60]; /* filename, null padded */} CSDescriptor_t;typedef struct CSClient_s{ PRLock *ml; PRThread *thread; PRCondVar *stateChange; PRNetAddr serverAddress; CSState_t state; /* statistics */ PRIntervalTime started, stopped; PRUint32 operations, bytesTransferred;} CSClient_t;#define TEST_LOG(l, p, a) \ do { \ if (debug_mode || (p <= verbosity)) printf a; \ } while (0)PRLogModuleInfo *cltsrv_log_file = NULL;#define MY_ASSERT(_expr) \ ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))#define TEST_ASSERT(_expr) \ ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__))static void _MY_Assert(const char *s, const char *file, PRIntn ln){ PL_PrintError(NULL);#if DEBUG PR_Assert(s, file, ln);#endif} /* _MW_Assert */static PRBool Aborted(PRStatus rv){ return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ? PR_TRUE : PR_FALSE;}static void TimeOfDayMessage(const char *msg, PRThread* me){ char buffer[100]; PRExplodedTime tod; PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod); (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, ("%s(0x%p): %s\n", msg, me, buffer));} /* TimeOfDayMessage */static void PR_CALLBACK Client(void *arg){ PRStatus rv; PRIntn index; char buffer[1024]; PRFileDesc *fd = NULL; PRUintn clipping = DEFAULT_CLIPPING; CSClient_t *client = (CSClient_t*)arg; PRThread *me = client->thread = PR_CurrentThread(); CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT); for (index = 0; index < sizeof(buffer); ++index) buffer[index] = (char)index; client->started = PR_IntervalNow(); PR_Lock(client->ml); client->state = cs_run; PR_NotifyCondVar(client->stateChange); PR_Unlock(client->ml); TimeOfDayMessage("Client started at", me); while (cs_run == client->state) { PRInt32 bytes, descbytes, filebytes, netbytes; (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer)); TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, ("\tClient(0x%p): connecting to server at %s\n", me, buffer)); fd = PR_Socket(domain, SOCK_STREAM, protocol); TEST_ASSERT(NULL != fd); rv = PR_Connect(fd, &client->serverAddress, timeout); if (PR_FAILURE == rv) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): conection failed\n", me)); goto aborted; } memset(descriptor, 0, sizeof(*descriptor)); descriptor->size = PR_htonl(descbytes = rand() % clipping); PR_snprintf( descriptor->filename, sizeof(descriptor->filename), "CS%p%p-%p.dat", client->started, me, client->operations); TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes)); bytes = PR_Send( fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout); if (sizeof(CSDescriptor_t) != bytes) { if (Aborted(PR_FAILURE)) goto aborted; if (PR_IO_TIMEOUT_ERROR == PR_GetError()) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): send descriptor timeout\n", me)); goto retry; } } TEST_ASSERT(sizeof(*descriptor) == bytes); netbytes = 0; while (netbytes < descbytes) { filebytes = sizeof(buffer); if ((descbytes - netbytes) < filebytes) filebytes = descbytes - netbytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tClient(0x%p): sending %d bytes\n", me, filebytes)); bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); if (filebytes != bytes) { if (Aborted(PR_FAILURE)) goto aborted; if (PR_IO_TIMEOUT_ERROR == PR_GetError()) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): send data timeout\n", me)); goto retry; } } TEST_ASSERT(bytes == filebytes); netbytes += bytes; } filebytes = 0; while (filebytes < descbytes) { netbytes = sizeof(buffer); if ((descbytes - filebytes) < netbytes) netbytes = descbytes - filebytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tClient(0x%p): receiving %d bytes\n", me, netbytes)); bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); if (-1 == bytes) { if (Aborted(PR_FAILURE)) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): receive data aborted\n", me)); goto aborted; } else if (PR_IO_TIMEOUT_ERROR == PR_GetError()) TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): receive data timeout\n", me)); else TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): receive error (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto retry; } if (0 == bytes) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\t\tClient(0x%p): unexpected end of stream\n", PR_CurrentThread())); break; } filebytes += bytes; } rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH); if (Aborted(rv)) goto aborted; TEST_ASSERT(PR_SUCCESS == rv);retry: (void)PR_Close(fd); fd = NULL; TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, ("\tClient(0x%p): disconnected from server\n", me)); PR_Lock(client->ml); client->operations += 1; client->bytesTransferred += 2 * descbytes; rv = PR_WaitCondVar(client->stateChange, rand() % clipping); PR_Unlock(client->ml); if (Aborted(rv)) break; }aborted: client->stopped = PR_IntervalNow(); PR_ClearInterrupt(); if (NULL != fd) rv = PR_Close(fd); PR_Lock(client->ml); client->state = cs_exit; PR_NotifyCondVar(client->stateChange); PR_Unlock(client->ml); PR_DELETE(descriptor); TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, ("\tClient(0x%p): stopped after %u operations and %u bytes\n", PR_CurrentThread(), client->operations, client->bytesTransferred));} /* Client */static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server){ PRStatus drv, rv; char buffer[1024]; PRFileDesc *file = NULL; PRThread * me = PR_CurrentThread(); PRInt32 bytes, descbytes, netbytes, filebytes = 0; CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT); TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tProcessRequest(0x%p): receiving desciptor\n", me)); bytes = PR_Recv( fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout); if (-1 == bytes) { rv = PR_FAILURE; if (Aborted(rv)) goto exit; if (PR_IO_TIMEOUT_ERROR == PR_GetError()) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tProcessRequest(0x%p): receive timeout\n", me)); } goto exit; } if (0 == bytes) { rv = PR_FAILURE; TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tProcessRequest(0x%p): unexpected end of file\n", me)); goto exit; } descbytes = PR_ntohl(descriptor->size); TEST_ASSERT(sizeof(*descriptor) == bytes); TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n", me, descbytes, descriptor->filename)); file = PR_Open( descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666); if (NULL == file) { rv = PR_FAILURE; if (Aborted(rv)) goto aborted; if (PR_IO_TIMEOUT_ERROR == PR_GetError()) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tProcessRequest(0x%p): open file timeout\n", me)); goto aborted; } } TEST_ASSERT(NULL != file);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -