📄 socket.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. *//*************************************************************************** Name: socket.c**** Description: Test socket functionality.**** Modification History:*/#include "primpl.h"#include "plgetopt.h"#include <stdio.h>#include <string.h>#include <errno.h>#ifdef XP_UNIX#include <sys/mman.h>#endif#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)#include <pthread.h>#endif#ifdef WIN32#include <process.h>#endifstatic int _debug_on = 0;static int test_cancelio = 0;#ifdef XP_MAC#include "prlog.h"#include "prsem.h"int fprintf(FILE *stream, const char *fmt, ...){ PR_LogPrint(fmt); return 0;}#define printf PR_LogPrintextern void SetupMacPrintfLog(char *logFile);#else#include "obsolete/prsem.h"#endif#ifdef XP_PC#define mode_t int#endif#define DPRINTF(arg) if (_debug_on) printf arg#ifdef XP_PCchar *TEST_DIR = "prdir";char *SMALL_FILE_NAME = "prsmallf";char *LARGE_FILE_NAME = "prlargef";#elsechar *TEST_DIR = "/tmp/prsocket_test_dir";char *SMALL_FILE_NAME = "/tmp/prsocket_test_dir/small_file";char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file";#endif#define SMALL_FILE_SIZE (3 * 1024) /* 3 KB */#define SMALL_FILE_OFFSET_1 (512)#define SMALL_FILE_LEN_1 (1 * 1024) /* 1 KB */#define SMALL_FILE_OFFSET_2 (75)#define SMALL_FILE_LEN_2 (758)#define SMALL_FILE_OFFSET_3 (1024)#define SMALL_FILE_LEN_3 (SMALL_FILE_SIZE - SMALL_FILE_OFFSET_3)#define SMALL_FILE_HEADER_SIZE (64) /* 64 bytes */#define SMALL_FILE_TRAILER_SIZE (128) /* 128 bytes */#define LARGE_FILE_SIZE (3 * 1024 * 1024) /* 3 MB */#define LARGE_FILE_OFFSET_1 (0)#define LARGE_FILE_LEN_1 (2 * 1024 * 1024) /* 2 MB */#define LARGE_FILE_OFFSET_2 (64)#define LARGE_FILE_LEN_2 (1 * 1024 * 1024 + 75)#define LARGE_FILE_OFFSET_3 (2 * 1024 * 1024 - 128)#define LARGE_FILE_LEN_3 (LARGE_FILE_SIZE - LARGE_FILE_OFFSET_3)#define LARGE_FILE_OFFSET_4 PR_GetPageSize()#define LARGE_FILE_LEN_4 769#define LARGE_FILE_HEADER_SIZE (512)#define LARGE_FILE_TRAILER_SIZE (64)#define BUF_DATA_SIZE (2 * 1024)#define TCP_MESG_SIZE 1024/* * set UDP datagram size small enough that datagrams sent to a port on the * local host will not be lost */#define UDP_DGRAM_SIZE 128#define NUM_TCP_CLIENTS 5 /* for a listen queue depth of 5 */#define NUM_UDP_CLIENTS 10#ifndef XP_MAC#define NUM_TRANSMITFILE_CLIENTS 4#else/* Mac can't handle more than 2* (3Mb) allocations for large file size buffers */#define NUM_TRANSMITFILE_CLIENTS 2#endif#define NUM_TCP_CONNECTIONS_PER_CLIENT 5#define NUM_TCP_MESGS_PER_CONNECTION 10#define NUM_UDP_DATAGRAMS_PER_CLIENT 5#define TCP_SERVER_PORT 10000#define UDP_SERVER_PORT TCP_SERVER_PORT#define SERVER_MAX_BIND_COUNT 100static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS;static PRInt32 num_udp_clients = NUM_UDP_CLIENTS;static PRInt32 num_transmitfile_clients = NUM_TRANSMITFILE_CLIENTS;static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT;static PRInt32 tcp_mesg_size = TCP_MESG_SIZE;static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION;static PRInt32 num_udp_datagrams_per_client = NUM_UDP_DATAGRAMS_PER_CLIENT;static PRInt32 udp_datagram_size = UDP_DGRAM_SIZE;static PRInt32 thread_count;PRUint16 server_domain = PR_AF_INET, client_domain = PR_AF_INET;/* an I/O layer that uses the emulated senfile method */static PRDescIdentity emuSendFileIdentity;static PRIOMethods emuSendFileMethods;int failed_already=0;typedef struct buffer { char data[BUF_DATA_SIZE];} buffer;PRNetAddr tcp_server_addr, udp_server_addr;typedef struct Serve_Client_Param { PRFileDesc *sockfd; /* socket to read from/write to */ PRInt32 datalen; /* bytes of data transfered in each read/write */} Serve_Client_Param;typedef struct Server_Param { PRSemaphore *addr_sem; /* sem to post on, after setting up the address */ PRMonitor *exit_mon; /* monitor to signal on exit */ PRInt32 *exit_counter; /* counter to decrement, before exit */ PRInt32 datalen; /* bytes of data transfered in each read/write */} Server_Param;typedef struct Client_Param { PRNetAddr server_addr; PRMonitor *exit_mon; /* monitor to signal on exit */ PRInt32 *exit_counter; /* counter to decrement, before exit */ PRInt32 datalen; PRInt32 udp_connect; /* if set clients connect udp sockets */} Client_Param;/* the sendfile method in emuSendFileMethods */static PRInt32 PR_CALLBACKemu_SendFile(PRFileDesc *sd, PRSendFileData *sfd, PRTransmitFileFlags flags, PRIntervalTime timeout){ return PR_EmulateSendFile(sd, sfd, flags, timeout);}/* the transmitfile method in emuSendFileMethods */static PRInt32 PR_CALLBACKemu_TransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout){ PRSendFileData sfd; sfd.fd = fd; sfd.file_offset = 0; sfd.file_nbytes = 0; sfd.header = headers; sfd.hlen = hlen; sfd.trailer = NULL; sfd.tlen = 0; return emu_SendFile(sd, &sfd, flags, timeout);}/* * readn * read data from sockfd into buf */static PRInt32readn(PRFileDesc *sockfd, char *buf, int len){ int rem; int bytes; int offset = 0; int err; PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; if (test_cancelio) timeout = PR_SecondsToInterval(2); for (rem=len; rem; offset += bytes, rem -= bytes) { DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n", PR_GetCurrentThread(), rem));retry: bytes = PR_Recv(sockfd, buf + offset, rem, 0, timeout); DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n", PR_GetCurrentThread(), bytes)); if (bytes < 0) {#ifdef WINNT printf("PR_Recv: error = %d oserr = %d\n",(err = PR_GetError()), PR_GetOSError()); if ((test_cancelio) && (err == PR_IO_TIMEOUT_ERROR)) { if (PR_NT_CancelIo(sockfd) != PR_SUCCESS) printf("PR_NT_CancelIO: error = %d\n",PR_GetError()); timeout = PR_INTERVAL_NO_TIMEOUT; goto retry; }#endif return -1; } } return len;}/* * writen * write data from buf to sockfd */static PRInt32writen(PRFileDesc *sockfd, char *buf, int len){ int rem; int bytes; int offset = 0; for (rem=len; rem; offset += bytes, rem -= bytes) { DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n", PR_GetCurrentThread(), rem)); bytes = PR_Send(sockfd, buf + offset, rem, 0, PR_INTERVAL_NO_TIMEOUT); DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n", PR_GetCurrentThread(), bytes)); if (bytes <= 0) return -1; } return len;}/* * Serve_Client * Thread, started by the server, for serving a client connection. * Reads data from socket and writes it back, unmodified, and * closes the socket */static void PR_CALLBACKServe_Client(void *arg){ Serve_Client_Param *scp = (Serve_Client_Param *) arg; PRFileDesc *sockfd; buffer *in_buf; PRInt32 bytes, j; sockfd = scp->sockfd; bytes = scp->datalen; in_buf = PR_NEW(buffer); if (in_buf == NULL) { fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); failed_already=1; goto exit; } for (j = 0; j < num_tcp_mesgs_per_connection; j++) { /* * Read data from client and send it back to the client unmodified */ if (readn(sockfd, in_buf->data, bytes) < bytes) { fprintf(stderr,"prsocket_test: ERROR - Serve_Client:readn\n"); failed_already=1; goto exit; } /* * shutdown reads, after the last read */ if (j == num_tcp_mesgs_per_connection - 1) if (PR_Shutdown(sockfd, PR_SHUTDOWN_RCV) < 0) { fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n"); } DPRINTF(("Serve_Client [0x%lx]: inbuf[0] = 0x%lx\n",PR_GetCurrentThread(), (*((int *) in_buf->data)))); if (writen(sockfd, in_buf->data, bytes) < bytes) { fprintf(stderr,"prsocket_test: ERROR - Serve_Client:writen\n"); failed_already=1; goto exit; } } /* * shutdown reads and writes */ if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n"); failed_already=1; }exit: PR_Close(sockfd); if (in_buf) { PR_DELETE(in_buf); }}PRThread* create_new_thread(PRThreadType type, void (*start)(void *arg), void *arg, PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize, PRInt32 index){PRInt32 native_thread = 0; PR_ASSERT(state == PR_UNJOINABLE_THREAD);#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32) switch(index % 4) { case 0: scope = (PR_LOCAL_THREAD); break; case 1: scope = (PR_GLOBAL_THREAD); break; case 2: scope = (PR_GLOBAL_BOUND_THREAD); break; case 3: native_thread = 1; break; default: PR_ASSERT(!"Invalid scope"); break; } if (native_thread) {#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) pthread_t tid; if (!pthread_create(&tid, NULL, (void * (*)(void *)) start, arg)) return((PRThread *) tid); else return (NULL);#else HANDLE thandle; unsigned tid; thandle = (HANDLE) _beginthreadex( NULL, stackSize, (unsigned (__stdcall *)(void *))start, arg, 0, &tid); return((PRThread *) thandle);#endif } else { return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); }#else return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));#endif}/* * TCP Server * Server Thread * Bind an address to a socket and listen for incoming connections * Start a Serve_Client thread for each incoming connection. */static void PR_CALLBACKTCP_Server(void *arg){ PRThread *t; Server_Param *sp = (Server_Param *) arg; Serve_Client_Param *scp; PRFileDesc *sockfd, *newsockfd; PRNetAddr netaddr; PRInt32 i; /* * Create a tcp socket */ if ((sockfd = PR_OpenTCPSocket(server_domain)) == NULL) { fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n"); goto exit; } memset(&netaddr, 0 , sizeof(netaddr)); if (PR_SetNetAddr(PR_IpAddrAny, server_domain, TCP_SERVER_PORT, &netaddr) == PR_FAILURE) { fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); goto exit; } /* * try a few times to bind server's address, if addresses are in * use */ i = 0; while (PR_Bind(sockfd, &netaddr) < 0) { if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { netaddr.inet.port += 2; if (i++ < SERVER_MAX_BIND_COUNT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -