#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
/*内部宏声明*/
#define HOSTNAMESIZE 255
#define PORTBUFSIZE 10
#define HOST_NAME "127.0.0.1"
#define TEST_PORT "12865"
//#define LISTEN_PORT "5000"
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define DO_TCP_STREAM 22
#define TCP_STREAM_RESPONSE 21
/*内部全局变量声明*/
char rem_host_name[HOSTNAMESIZE];
char local_host_name[HOSTNAMESIZE];
char rem_port[PORTBUFSIZE];
char local_port[PORTBUFSIZE];
char listen_port[PORTBUFSIZE];
int rem_addr_family;
int local_addr_family;
char *server_name;
FILE *where = stdout;
int server_control;
struct timeval time_begin, time_stop;
float lib_elapsed;
union netbench_request_struct netbench_request;
union netbench_response_struct netbench_response;
/*define send and recv size vairables*/
static int ls_size_req,
lr_size_req,
ls_size,
lr_size,
rs_size_req,
rr_size_req,
rs_size,
rr_size;
int recv_size;
int recv_width;
/*内部结构体声明*/
/*struct addrinfo*/
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
};
struct tcp_stream_request_struct {
int send_buf_size;
int recv_buf_size; /* how big does the client want it - the */
/* receive socket buffer that is */
int receive_size; /* how many bytes do we want to receive at one */
/* time? */
int recv_alignment; /* what is the alignment of the receive */
/* buffer? */
int recv_offset; /* and at what offset from that alignment? */
int no_delay; /* do we disable the nagle algorithm for send */
/* coalescing? */
int measure_cpu; /* does the client want server cpu utilization */
/* measured? */
float cpu_rate; /* do we know how fast the cpu is already? */
int test_length; /* how long is the test? */
int so_rcvavoid; /* do we want the remote to avoid copies on */
/* receives? */
int so_sndavoid; /* do we want the remote to avoid send copies? */
int dirty_count; /* how many integers in the receive buffer */
/* should be made dirty before calling recv? */
int clean_count; /* how many integers should be read from the */
/* recv buffer before calling recv? */
int port; /* the port to which the recv side should bind
to allow netperf to run through those evil
firewall things */
int ipfamily; /* the address family of ipaddress */
};
struct tcp_stream_response_struct {
int recv_buf_size; /* how big does the client want it */
int receive_size;
int no_delay;
int measure_cpu; /* does the client want server cpu */
int test_length; /* how long is the test? */
int send_buf_size;
int data_port_number; /* connect to me here */
float cpu_rate; /* could we measure */
int so_rcvavoid; /* could the remote avoid receive copies? */
int so_sndavoid; /* could the remote avoid send copies? */
};
struct tcp_stream_results_struct {
double bytes_received;
unsigned int recv_calls;
float elapsed_time; /* how long the test ran */
float cpu_util; /* -1 if not measured */
float serv_dem; /* -1 if not measured */
int cpu_method; /* how was cpu util measured? */
int num_cpus; /* how many CPUs had the remote? */
};
union netbench_request_struct {
struct {
int request_type;
int dummy;
int test_specific_data[MAXSPECDATA];
} content;
double dummy;
};
union netbench_response_struct {
struct {
int response_type;
int serv_errno;
int test_specific_data[MAXSPECDATA];
} content;
double dummy;
};
struct ring_elt {
struct ring_elt *next; /* next element in the ring */
char *buffer_base; /* in case we have to free it at somepoint */
char *buffer_ptr; /* the aligned and offset pointer */
};
/*start*/
int main(int argc, char **argv)
{
server_name = (char *)malloc(strlen(argv[0]) + 1);
if(server_name == NULL){
fprintf(where,"%s malloc (%d) failed!/n",server_name, strlen(argv[0]) + 1);
fflush(where);
return (1);
}
strcpy(server_name, argv[0]);
set_defaults_opt();
set_user_opt(argc, argv);
/*set up server*/
set_up_server(local_host_name, listen_port, local_addr_family);
return (0);
}
/*******************************************************
函数功能:设置全局变量的默认参数
输入参数:无
输出参数:无
作者:
时间:2009/08/7
描述:新生成函数
*********************************************************/
void set_defaults_opt()
{
strncpy(local_host_name, "0.0.0.0", sizeof(local_host_name));
local_addr_family = AF_INET;
strncpy(listen_port, TEST_PORT, sizeof(listen_port));
/*set */
recv_size = 0;
recv_width = 0;
}
/*********************************************************
函数功能:设置全局变量的用户传入的参数
输入参数:无
输出参数:无
作者:
时间:2009/08/7
描述:新生成函数
***********************************************************/
void set_user_opt(int argc, char ** argv)
{
int c ;
argc--;
argv++;
while((c= getopt(argc, argv)) != EOF)
{
switch (c) {
case '?':
usage();
exit(0);
case 'p':
case 'P':
argc--;
argv++;
strncpy(local_port,*argv[],PORTBUFSIZE);
break;
default:
argc--;
argv++;
break;
}
}
}
/*******************************************************
函数功能:扫描用户输入的参数
输入参数:无
输出参数:无
作者:
时间:2009/08/7
描述:新生成函数
*********************************************************/
int getopt(int argc, char **argv)
{
char *PtrArg = *argv[];
if('-' == *PtrArg)
{
return (*(++PtrArg));
}
else
{
return 0;
}
}
/*******************************************************
函数功能:打印使用方法
输入参数:无
输出参数:无
作者:
时间:2009/07/31
描述:新生成函数
*********************************************************/
void usage()
{
fprintf(where,"./%s -P port_num/n",server_name);
fprintf(where,"each parameter as follows:/n");
fprintf(where,">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>/n");
fprintf(where,"P:local host port number/n");
fprintf(where,">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>/n");
fflush(where);
}
/*******************************************************
函数功能:
输入参数:无
输出参数:无
作者:
时间:2009/08/7
描述:新生成函数
*********************************************************/
void set_up_server(char hostname[], char port[], int af)
{
struct addrinfo local_res;
struct sockaddr_in peeraddr;
int error;
//int server_control;
int on = 1;
#ifdef DEBUG_INFO
fprintf(where, "set_up_server called with host '%s' port '%s af_family '%d'/n", hostname, port, af);
fflush(where);
#endif
memset(&local_res, 0, sizeof(struct addrinfo));
local_res.ai_family = af;
local_res.ai_socktype = SOCK_STREAM;
local_res.ai_protocol = IPPROTO_TCP;
local_res.ai_flags = 0;
error = get_addr_info(hostname, port, &local_res);
if(error < 0){
fprintf(where, "get_addr_info error/n");
fflush(where);
}
server_control = socket(local_res->ai_family, SOCK_STREAM, 0);
if(server_control == INVALID_SOCKET){
fprintf(where, "server_control create failed!/n");
fflush(where);
exit(-1);
}
if(setsockopt(server_control,
SOL_SOCKET,
SO_REUSEADDR,
(char *)&on,
sizeof(on)) == SOCKET_ERROR){
fprintf(where, "setsockopt error/n");
fflush(where);
exit(-1);
}
if((bind (server_control,
local_res->ai_addr,
local_res->ai_addrlen) != SOCKET_ERROR) &&
(listen (server_control, 5) !=SOCKET_ERROR)) {
#ifdef DEBUG_INFO
fprintf(where, "starting netserver at hostname %s port %s and family %d/n",
hostname, port, af);
fflush(where);
#endif
}
else
{
fprintf(where,"set_up_server failed a bind or listen call/n");
fflush(where);
exit(-1);
}
for(;;)
{
if((server_sock = accept(server_control,
(struct sockaddr *)&peeraddr,
sizeof(peeraddr))) == INVALID_SOCKET)
{
fprintf(where, "set_up_server: accept failed error/n");
fflush(where);
exit(-1);
}
signal(SIGCHLD, SIG_IGN);
switch(fork())
{
case -1:
exit(-1);
case 0:
close(server_control);
process_request();
exit(0);
default:
close(server_sock);
break;
}
}
return;
}
/***************************************************************
函数功能:
输入参数:无
输出参数:无
作者:
时间:2009/08/7
描述:新生成函数
*****************************************************************/
int get_addr_info(char *HostName,
char *HostPort,
struct addrinfo *info)
{
u16 port;
struct in_addr temp_addr;
struct sockaddr_in* temp_sock = NULL;
/*get port number and ip address*/
if(HostPort != NULL)
{
if(is_integer(HostPort))
{
port = htons(atoi(HostPort));
}
else{
port = htons(0);
}
}
else
{
port = htons(0);
}
if(HostName != NULL)
{
if(is_address(HostName))
{
temp_addr.s_addr = inet_addr(nodename);
}
else
{
temp_addr.s_addr = htonl(INADDR_ANY);
}
}
else
{
temp_addr.s_addr = htonl(INADDR_ANY);
}
/*fill the info->ai_addr and info->ai_addrlen*/
info->ai_addrlen = sizeof(struct sockaddr_in);
info->ai_addr = (struct sockaddr*)malloc(sizeof(sockaddr_in));
if(info->ai_addr == NULL){
fprintf(where,"ai_addr malloc failed/n");
fflush(where);
free(info->ai_addr);
return SOCKET_ERROR;
}
temp_sock = (struct sockaddr_in*)info->ai_addr;
temp_sock->sin_family = AF_NORMAL;
temp_sock->sin_port = port;
memcpy(&temp_sock->sin_addr, &temp_addr, sizeof(struct in_addr));
return (0);
}
/***************************************************************
函数功能:处理请求类型,进入相应的处理函数
输入参数:无
输出参数:无
作者:
时间:2009/08/7
描述:新生成函数
*****************************************************************/
void process_request()
{
while(1){
recv_request();
switch(netbench_request.content.request_type) {
case DO_TCP_STREAM
recv_tcp_stream();
break;
default:
exit(0);
}
}
}
/***************************************************************
函数功能:接收请求信息
输入参数:无
输出参数:无
作者:
时间:2009/08/7
描述:新生成函数
*****************************************************************/
void recv_request()
{
int tot_bytes_recvd = 0;
int bytes_recvd = 0;
int bytes_left;
char *buf = (char *)&netbench_request;
int buflen = sizeof(netbench_request);
bytes_left = buflen;
while((tot_bytes_recvd != buflen) && (bytes_recvd = recv(server_sock, buf, bytes_left, 0)) > 0){
tot_bytes_recvd += bytes_recvd;
buf += bytes_recvd;
bytes_left -= bytes_recvd;
}
#ifdef DEBUG_INFO
fprintf(where,"recv_request: received %d bytes of request./n",tot_bytes_recvd);
fflush(where);
#endif DEBUG_INFO
if(bytes_recvd <= 0){
fprintf(where,"recv_request: error on recv/n");
fflush(where);
exit(1);
}
if(tot_bytes_recvd < buflen){
fprintf(where, "recv_request: partial request received of %d bytes/n",tot_bytes_recvd);
fflush(where);
exit(1);
}
}
/***************************************************************
函数功能:接收TCP 块数据
输入参数:无
输出参数:无
作者:
时间:2009/08/7
描述:新生成函数
*****************************************************************/
void recv_tcp_stream()
{
struct addrinfo local_data_res;
struct sockaddr_in server_addr, peer_addr;
int addrlen;
char local_data_name[HOSTNAMESIZE];
char port[PORTBUFSIZE];
int error;
unsigned int receive_calls;
float elapsed_time;
double bytes_received;
int lis_sock,data_sock;
int recv_len;
struct ring_elt *recv_ring;
#ifdef DIRTY
int *message_int_ptr;
int dirty_count;
int clean_count;
int i;
#endif
struct tcp_stream_request_struct *tcp_stream_request;
struct tcp_stream_response_struct *tcp_stream_response;
struct tcp_stream_results_struct *tcp_stream_results;
tcp_stream_request =
(struct tcp_stream_request_struct *)netbench_request.content.test_specific_data;
tcp_stream_response =
(struct tcp_stream_response_struct *)netbench_response.content.test_specific_data;
tcp_stream_results =
(struct tcp_stream_results_struct *)netbench_response.content.test_specific_data;
memset(tcp_stream_request, 0, sizeof(struct tcp_stream_request_struct));
memset(tcp_stream_response, 0, sizeof(struct tcp_stream_response_struct));
memset(tcp_stream_results, 0, sizeof(struct tcp_stream_results_struct));
#ifdef DEBUG_INFO
fprintf(where, "netbench_server:recv_tcp_stream :entering.../n");
fflush(where);
#endif
netbench_response.content.response_type = TCP_STREAM_RESPONSE;
#ifdef DEBUG_INFO
fprintf(where, "recv_tcp_stream: request type is %d",netbench_response.content.response_type);
fflush(where);
#endif
ls_size_req = tcp_stream_request->send_buf_size;
lr_size_req = tcp_stream_request->recv_buf_size;
set_hostanme_port(local_data_name, port, tcp_stream_request->port);
memset(&local_data_res, 0, sizeof(struct addrinfo));
local_data_res.ai_family = tcp_stream_request->ipfamily;
local_data_res.ai_socktype = SOCK_STREAM;
local_data_res.ai_protocol = IPPROTO_TCP;
local_data_res.ai_flags = 0;
error = get_addr_info(local_data_name, port, &local_data_res);
if(error < 0){
fprintf(where, "get_addr_info error/n");
fflush(where);
}
lis_sock = create_data_sock(&local_data_res);
if(lis_sock == INVALID_SOCKET) {
fprintf(where,"create listen socket error!/n");
fflush(where);
exit(-1);
}
if(tcp_stream_request->receive_size == 0) {
if(lr_size > 0) {
recv_size = lr_size;
}
else {
recv_size = 4096;
}
}
else {
recv_size = tcp_stream_request->receive_size;
}
#ifdef DEBUG_INFO
fprintf(where, "set recv buff size is %d/n",recv_size);
fflush(where);
#endif
if (recv_width == 0){
recv_width = (lr_size/recv_size) + 1;
if(recv_width == 1) recv_width++;
}
recv_ring = alloc_ring_buff(recv_width,
recv_size,
tcp_stream_request->recv_alignment,
tcp_stream_request->recv_offset);
#ifdef DEBUG_INFO
fprintf(where,"recv_tcp_stream:receive alignment and offset set.../n");
fflush(where);
#endif
if(listen(lis_sock, 5) == SOCKET_ERROR) {
fprintf(where,"recv_tcp_stream: listen error/n");
fflush(where);
close(lis_sock);
exit(-1);
}
addrlen = sizeof(server_addr);
if(getsockname(lis_sock,
(struct sockaddr *)&server_addr,
&addrlen) == SOCKET_ERROR) {
fprintf(where,"recv_tcp_stream: getsockname error!/n");
fflush(where);
close(lis_sock);
exit(-1);
}
tcp_stream_response->data_port_number = (int) ntohs(server_addr.sin_port);
netbench_response.content.serv_errno = 0;
tcp_stream_response->send_buf_size = ls_size;
tcp_stream_response->recv_buf_size = lr_size;
tcp_stream_response->receive_size = recv_size;
tcp_stream_response->no_delay = 0;
tcp_stream_response->so_rcvavoid = 0;
tcp_stream_response->so_sndavoid = 0;
send_response();
addrlen = sizeof(peer_addr);
if((data_sock = accept(lis_sock,
(struct sockaddr *)&peer_addr,
&addrlen)) == INVALID_SOCKET) {
fprintf(where,"recv_tcp_stream:accept error!/n");
fflush(where);
close(lis_sock);
exit(-1);
}
cpu_start();
#ifdef DIRTY
srand((int)getpid());
dirty_count = tcp_stream_request->dirty_count;
clean_count = tcp_stream_request->clean_count;
message_int_ptr = (int *)recv_ring->buffer_ptr;
for(i = 0; i < dirty_count; i++) {
*message_int_ptr = rand();
message_int_ptr++;
}
for(i = 0; i < clean_count; i++) {
dirty_count = *message_int_ptr;
message_int_ptr++;
}
#endif
bytes_received = 0;
receive_calls = 0;
while((recv_len = recv(data_sock, recv_ring->buffer_ptr, recv_size, 0)) != 0) {
if(recv_len < 0) {
fprintf(where, "recv_tcp_stream recv error!/n");
fflush(where);
exit(-1);
}
bytes_received += recv_len;
receive_calls++;
recv_ring = recv_ring->next;
#ifdef DIRTY
message_int_ptr = (int *)(recv_ring->buffer_ptr);
for (i = 0; i < dirty_count; i++) {
*message_int_ptr = rand();
message_int_ptr++;
}
for (i = 0; i < clean_count; i++) {
dirty_count = *message_int_ptr;
message_int_ptr++;
}
#endif
}
if(shutdown(data_sock, 1) == SOCKET_ERROR) {
fprintf(where,"shutdown data_sock error!/n");
fflush(where);
exit(-1);
}
cpu_stop(&elapsed_time);
#ifdef DEBUG_INFO
fprintf(where,
"recv_tcp_stream: got %g bytes/n",
bytes_received);
fprintf(where,
"recv_tcp_stream: got %d recvs/n",
receive_calls);
fflush(where);
#endif
tcp_stream_results->bytes_received = htond(bytes_received);
tcp_stream_results->elapsed_time = elapsed_time;
tcp_stream_results->recv_calls = receive_calls;
tcp_stream_results->cpu_method = 0;
tcp_stream_results->num_cpus = 0;
send_response();
/*close sock*/
close(data_sock);
close(lis_sock);
}
/*******************************************************
函数功能:记录测试的开始时间
输入参数:无
输出参数:无
作者:
时间:2009/08/2
描述:新生成函数
*********************************************************/
void cpu_start()
{
gettimeofday(&time_begin, NULL);
}
/*******************************************************
函数功能:记录测试的结束时间
输入参数:无
输出参数:无
作者:
时间:2009/08/2
描述:新生成函数
*********************************************************/
void cpu_stop(float *elapsed)
{
int sec;
int usec;
gettimeofday(&time_stop, NULL);
if (time_stop.tv_usec < time_begin.tv_usec) {
time_stop.tv_usec += 1000000;
time_stop.tv_sec -= 1;
}
sec = time_stop.tv_sec - time_begin.tv_sec;
usec = time_stop.tv_usec - time_begin.tv_usec;
lib_elapsed = (float)sec + ((float)usec/(float)1000000.0);
*elapsed = lib_elapsed;
}
/*******************************************************
函数功能:回应函数
输入参数:无
输出参数:无
作者:
时间:2009/08/2
描述:新生成函数
*********************************************************/
void send_response()
{
int counter = 0;
int bytes_send = 0;
#ifdef DEBUG_INFO
fprintf(where,"send response.../n");
fflush(where);
#endif
if ((bytes_send = send(server_control,
(char *)&netbench_response,
sizeof(netbench_response),
0)) != sizeof(netbench_response)) {
perror("send_response: send call failure");
fprintf(where, "BytesSend: %d/n", bytes_send);
exit(1);
}
}
/*******************************************************
函数功能:分配缓冲区
输入参数:无
输出参数:无
作者:
时间:2009/08/2
描述:新生成函数
*********************************************************/
struct ring_elt *alloc_ring_buff(unsigned int width, unsigned int size, int align, int offset)
{
struct ring_elt *first_link = NULL;
struct ring_elt *temp_link = NULL;
struct ring_elt *prev_link;
int i;
int malloc_size;
malloc_size = size + align + offset;
assert(width >= 1);
prev_link = NULL;
for(i = 1; i <= width; i++){
temp_link = (struct ring_elt *)malloc(sizeof(struct ring_elt));
if(temp_link == NULL){
printf("malloc(%u) failed!/n", sizeof(struct ring_elt));
free(temp_link);
exit(1);
}
if(i == 1){
first_link = temp_link;
prev_link = temp_link;
}
temp_link->buffer_base = (char *)malloc(malloc_size);
if(temp_link->buffer_base == NULL){
printf("malloc(%d) failed!/n",malloc_size);
free(temp_link->buffer_base);
exit(1);
}
temp_link->buffer_ptr += offset;
//temp_link->next = NULL;
prev_link->next = temp_link;
if(i == width){
temp_link->next = first_link;
}
prev_link = temp_link;
}
return (first_link);
}
/*******************************************************
函数功能:
输入参数:无
输出参数:无
作者:
时间:2009/08/2
描述:新生成函数
*********************************************************/
void set_hostanme_port(char *hostname, char *portstr, int port)
{
strcpy(hostname, "0.0.0.0");
sprintf(portstr, "%u", port);
}
/*******************************************************
函数功能:创建传输数据套接字
输入参数:无
输出参数:无
作者:
时间:2009/08/2
描述:新生成函数
*********************************************************/
int create_data_sock(struct addrinfo *res)
{
int temp_sock;
int on = 1;
temp_sock = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol);
if(temp_sock == INVALID_SOCKET){
fprintf(where,
"netbench: create_data_socket: socket: errno %d fam %s type %s prot %s errmsg %s/n",
inet_ftos(res->ai_family),
inet_ttos(res->ai_socktype),
inet_ptos(res->ai_protocol));
fflush(where);
exit(1);
}
#ifdef DEBUG_INFO
fprintf(where,"create_data_socket: socket %d obtained.../n", temp_sock);
fflush(where);
#endif
/*set socket buffer size,send and recv*/
set_sock_buffer(temp_sock, SEND_SIZE, ls_size_req, &ls_size);
set_sock_buffer(temp_sock, RECV_SIZE, lr_size_req, &lr_size);
/*set reuse address property*/
if(setsockopt(temp_sock,
SOL_SOCKET.
SO_REUSEADDR,
&on,
sizeof(on)) < 0){
fprintf(where, "netbench:create_data_sock:SO_REUSEADDR failled/n");
fflush(where);
}
/*bind the sock*/
if (bind(temp_sock,
res->ai_addr,
res->ai_addrlen) < 0) {
fprintf(where,
"netbench: create_data_socket: data socket bind failed errno %d/n");
fprintf(where," port: %d/n",get_port_number(res));
fflush(where);
}
return(temp_sock);
}