之前写的SSL的性能测试程序

client.c

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/mman.h>

#define MAXBUF 1024
#define MAX_THREADS 100
#define SUBTHREADNUM 2

int pkgSize = 1024;
int threads = 10;
int times = 10;
int mode = 0;            //0-handshake 1-throughput 2-full
int sslversion = 1;        //0-SSLv2 1-SSLv3 2-SSLv23 3-TLSv1 4-TLSv1_1 5-TLSv1_2
char *ip = "127.0.0.1";
int port = 8701;
char *cipher = "AES128-SHA";
int debug = 0;
int showTitle = 1;


struct cpuinfo
{
    char name[20];
    unsigned int user;
    unsigned int nice;
    unsigned int system;
    unsigned int idle;
    unsigned int iowait;
    unsigned int irq;
    unsigned int softirq;
    unsigned int stealstolen;
    unsigned int guest;
};

void throughputTest();
void handshakeTest();
void fullTest();
void apacheTest();
void getCpuInfo (struct cpuinfo *cpu);
void calCpuUseRatio (struct cpuinfo *old, struct cpuinfo *new);
int getCpuTotalUseRatio();

struct shm_layout
{
    u_int64_t count[MAX_THREADS];
    u_int64_t t1[MAX_THREADS];
    u_int64_t t2[MAX_THREADS];
    int ready[MAX_THREADS];
    int done[MAX_THREADS];
    volatile int start;
    volatile int exit;
    volatile int stop;
};

struct subthread_layout
{
    u_int64_t starttime[SUBTHREADNUM];
    u_int64_t endtime[SUBTHREADNUM];
    u_int64_t count[SUBTHREADNUM];
};

struct shm_layout *shared_region = NULL;
struct subthread_layout subthread_region;
u_int64_t total_count = 0ull;
int thread_id = 0;
u_int64_t min_t1 = 0ull, max_t2 = 0ull;
u_int64_t total_throughput = 0;
int pid[100];
struct sockaddr_in dest;
char *buffer;
SSL_CTX *ctx;

void usage()
{
    printf("Usage: Client \n\
            -a   IP Addr (127.0.0.1) \n\
            -c   Cipher (AES128-SHA) \n\
            -p   Port (8701)\n\
            -s   Package Size (1024)\n\
            -t   Times (10)\n\
            -l   Threads (10)\n\
            -m   Mode (0-handshake 1-throughput 2-full 3-apachessl default 0)\n\
            -v   SSLVersion (0-SSLv2 1-SSLv3 2-SSLv23 3-TLSv1 4-TLSv1_1 5-TLSv1_2 default 1)\n\
            -d   Debug Info\n\
            -h   Help\n");
    exit(-1);
}

void min_max_times(int count, u_int64_t *t1, u_int64_t *t2, u_int64_t *min_t1, u_int64_t *max_t2)
{
    int i = 0;
    
    *min_t1 = t1[0];
    *max_t2 = t2[0];
    for(i = 1; i < count; i++)
    {
        if(t1[i] < *min_t1)
            *min_t1 = t1[i];
        if(t2[i] > *max_t2)
            *max_t2 = t2[i];
    }
}

u_int64_t apiTimeUs()
{
  struct timeval m_real1;
  u_int64_t temp;

  gettimeofday (&m_real1, 0);
  temp = m_real1.tv_sec;
  temp = (temp * 1000000) + m_real1.tv_usec;

  return temp;
}

char* randomStr()
{
    char *tmp = malloc(pkgSize * sizeof(char) + 1);
    int i;
    srand(time(NULL));
    for(i = 0; i < pkgSize; i++)
    {
        do
        {
            tmp[i] = rand() % 128;
        }while(!isprint(tmp[i]));
    }
    tmp[i] = '\0';
    return tmp;
}

int main(int argc, char **argv)
{
    char options[] = "a:c:m:t:s:p:v:l:hde";
    int opt;
    while((opt = getopt(argc, argv, options)) != -1)
    {
        switch(opt)
        {
            case 't':
                times = atoi(optarg);
                //printf("times:%d\n", times);
                break;
            case 'c':
                cipher = optarg;
                break;
            case 's':
                pkgSize = atoi(optarg);
                //printf("pkgSize:%d\n", pkgSize);
                break;
            case 'l':
                threads = atoi(optarg);
                //printf("threads:%d\n", threads);
                break;
            case 'p':
                port = atoi(optarg);
                //printf("port:%d\n", port);
                break;
            case 'a':
                ip = optarg;
                //printf("IP:%s\n", ip);
                break;
            case 'm':
                mode = atoi(optarg);
                //printf("type:%d\n", mode);
                break;
            case 'v':
                sslversion = atoi(optarg);  
                //printf("type:%d\n", sslversion);
                break;
            case 'd':
                debug = 1;
                break;
            case 'e':
                showTitle = 0;
                break;
            case 'h':
            default:
                usage();
                break;
        }
    }
    if(showTitle)
    {
        char *title[4] = {"Handshake Test", "Throughput Test", "HS And TP Test", "Apache SSL Test"};
        char *version[6] = {"SSLv2", "SSLv3", "SSLv23", "TLSv1", "TLSv1_1", "TLSv1_2"};
        char tmpStr[200] = {0};
        sprintf(tmpStr, "%s%s%s", "------------------------------------------------ ", title[mode], " ------------------------------------------------");
        printf("%s\n", tmpStr);
        printf("Server IP        Server Port        Thread Number        Times        Package Size        Cipher        Version\n");
        printf("%-20s %-20d %-15d %-16d %-12d %-16s %s\n", ip, port, threads, times, pkgSize, cipher, version[sslversion]);
    }
    int status[100];
    
    shared_region = mmap(NULL, sizeof(struct shm_layout), PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
    if(shared_region == MAP_FAILED)
    {
        printf("\n ERROR mapping \n");
        exit(1);
    }
    memset(shared_region, 0, sizeof(struct shm_layout));
    //SSL 库初始化,参看 ssl-server.c 代码
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    ctx = SSL_CTX_new(SSLv3_client_method());
    if (ctx == NULL) 
    {
        ERR_print_errors_fp(stdout);
        exit(1);
    }
    
    //初始化服务器端(对方)的地址和端口信息
    bzero(&dest, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(port);
    if (inet_aton(ip, (struct in_addr *) &dest.sin_addr.s_addr) == 0)
    {
        perror(argv[1]);
        exit(errno);
    }
    //printf("address created\n");
    
    if(!SSL_CTX_set_cipher_list(ctx, cipher))
    {
        SSL_CTX_free(ctx);
        exit(1);
    }
    buffer = randomStr();
    if(debug)
    {
        printf("buffer:%s\n", buffer);
    }
    int i;
    for(i = 0; i < threads; i++)
    {
        int kid = fork();
        if(kid < 0)
        {
            printf("Fork failed, Failed to create a new thread\n");
        }
        if(kid == 0)
        {
            thread_id = i;
            
            if(mode == 0)
            {
                handshakeTest();
            }
            else if(mode == 1)
            {
                throughputTest();
            }
            else if(mode == 2)
            {
                fullTest();
            }
            else if(mode == 3)
            {
                apacheTest();
            }
             
            shared_region->done[thread_id] = 1;
            sync();
            /* loop till all other threads are ready */
            while ((volatile int)shared_region->exit == 0)
            {
                sleep(1);
            }
            exit(0);
        }
        else
        {
            pid[i] = kid;
        }
    }
    
    for(i = 0;i < threads; i++)
    {
        while((volatile int)shared_region->ready[i] == 0)
        {
            usleep(10);
        }
    }
    shared_region->start = 1;
    u_int64_t starttime, endtime;
    starttime = apiTimeUs();
    sync();
    sleep(2);
    endtime = apiTimeUs();
    u_int64_t timeuse = endtime - starttime;
    while(timeuse < times * 1000000)
    {
        usleep(times * 1000000 - timeuse);
        endtime = apiTimeUs();
        timeuse = endtime - starttime;
        continue;
    }
    shared_region->stop = 1;
    for(i = 0;i < threads; i++)
    {
        while((volatile int)shared_region->done[i] == 0)
        {
            usleep(10);
        }
    }
    shared_region->exit = 1;
    sync();


    for(i = 0; i < threads; i++)
    {
        waitpid(pid[i], &status[i], 0);
    }

    for(i = 0;i < threads; i++)
    {
        total_count += shared_region->count[i];
    }
    
    min_max_times(threads, shared_region->t1, shared_region->t2, &min_t1, &max_t2);
    total_throughput = (u_int64_t)((total_count) * 1000000) / (max_t2 - min_t1);
    if(showTitle)
    {
        printf("                        --------------------------- Result ---------------------------\n");
    }
    if(mode == 1)
    {
        total_throughput = total_throughput * pkgSize / 1024 / 1024 * 8;
        if(showTitle)
        {
            printf("                        Package Size(Bytes)        Operations        Throughtput(Mbps)\n");
            printf("                              %-22d %-20llu %llu\n", pkgSize, (unsigned long long)total_count, (unsigned long long)total_throughput);
        }
        else
        {
            printf("                     %-22d %-20llu %llu\n", pkgSize, (unsigned long long)total_count, (unsigned long long)total_throughput);
        }
    }
    else if(mode == 0)
    {
        if(showTitle)
        {
            printf("                        Package Size(Bytes)        Operations         Operations/Sec\n");
            printf("                              %-23d %-20llu %llu\n", pkgSize, (unsigned long long)total_count, (unsigned long long)total_throughput);
        }
        else
        {
            printf("                     %-23d %-20llu %llu\n", pkgSize, (unsigned long long)total_count, (unsigned long long)total_throughput);
        }
    }
    else if(mode == 2)
    {
        if(showTitle)
        {
            printf("                        Module Size (Bytes)        Operations         Operations/Sec\n");
            printf("                              %-23d %-20llu %llu\n", 1024, (unsigned long long)total_count, (unsigned long long)total_throughput);
        }
        else
        {
            printf("                     %-23d %-20llu %llu\n", 1024, (unsigned long long)total_count, (unsigned long long)total_throughput);
        }
    }
    else if(mode == 3)
    {
        if(showTitle)
        {
            printf("                        Module Size (Bytes)        Operations         Operations/Sec\n");
            printf("                              %-23d %-20llu %llu\n", 1024, (unsigned long long)total_count, (unsigned long long)total_throughput);
        }
        else
        {
            printf("                     %-23d %-20llu %llu\n", 1024, (unsigned long long)total_count, (unsigned long long)total_throughput);
        }
    }
    //printf ("%-8d          %-8u         %-8%llu           %-dd8llu\n", buflen, total_throughput, total_count, max_t2-min_t1);
    munmap(shared_region, sizeof(struct shm_layout));
    fflush(stdout);
    sleep(2);
    return 0;
}


void handshakeTest()
{
    int sockfd, len;
    SSL *ssl;
    shared_region->ready[thread_id] = 1;
    sync();
    while ((volatile int)shared_region->start == 0);
    
    u_int64_t count = 0;
    u_int64_t starttime, endtime;
    starttime = apiTimeUs();
    while ((volatile int)shared_region->stop == 0)
    {
        //创建一个 socket 用于 tcp 通信
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            perror("Socket");
            break;
        }
        //printf("socket created!\n");
        
        //连接服务器
        if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
        {
            perror("Connect ");
            close(sockfd);
            break;
        }
        //printf("server connected!\n");

        //基于 ctx 产生一个新的 SSL
        ssl = SSL_new(ctx);
        if(count % 2 == 0)
        {
            SSL_free(ssl);
            ssl = SSL_new(ctx);
        }
        
        SSL_set_fd(ssl, sockfd);
        //建立 SSL 连接
        if (SSL_connect(ssl) == -1)
        {
            perror("SSL connect");
            SSL_free(ssl);
            close(sockfd);
            break;
        }
        else 
        {
            count++;
            if(debug)
            {
                if(count == 1)
                {
                    printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
                }
            }
        }
        // 关闭连接
        //SSL_shutdown(ssl);
        SSL_free(ssl);
        close(sockfd);
    }
    endtime = apiTimeUs();
    SSL_CTX_free(ctx);
    
    shared_region->count[thread_id] = count;
    shared_region->t1[thread_id] = starttime;
    shared_region->t2[thread_id] = endtime;
    sync();
}

void *createThread(void *arg)
{
    int sockfd, len;
    SSL *ssl;
    //创建一个 socket 用于 tcp 通信
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket");
        SSL_CTX_free(ctx);
        return;
    }
    //printf("socket created!\n");
    
    //连接服务器
    if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
    {
        perror("Connect ");
        close(sockfd);
        SSL_CTX_free(ctx);
        return;
    }
    //printf("server connected!\n");
    //基于 ctx 产生一个新的 SSL
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sockfd);
    //建立 SSL 连接
    if (SSL_connect(ssl) == -1)
    {
        //ERR_print_errors_fp(stderr);
        perror("SSL connect");
        SSL_free(ssl);
        close(sockfd);
        SSL_CTX_free(ctx);
        return;
    }
    else 
    {
        if(debug)
        {
            printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
        }
    }

    u_int64_t count = 0;
    int threadNum = (int)(*((int*)arg));
    subthread_region.starttime[threadNum] = apiTimeUs();
    while ((volatile int)shared_region->stop == 0)
    {
        len = SSL_write(ssl, buffer, strlen(buffer));
        if (len < 0)
        {
            printf("消息发送失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
            break;
        }
        else
        {
            count++;
            //printf("消息'%s'发送成功,共发送了%d个字节!\n", buffer, len);
        }
    }
    subthread_region.endtime[threadNum] = apiTimeUs();
    subthread_region.count[threadNum] = count;
    // 关闭连接
    SSL_shutdown(ssl);
    SSL_free(ssl);
    close(sockfd);
    return NULL;
}

void throughputTest()
{
    shared_region->ready[thread_id] = 1;
    sync();
    while ((volatile int)shared_region->start == 0);
/*    
    pthread_t thread[SUBTHREADNUM];
    int i;
    for(i = 0; i < SUBTHREADNUM; i++)
    {
        if(pthread_create(&thread[i], NULL, createThread, (void *)&i) != 0)//创建子线程
        {
            perror("pthread_create");
            break;
        }
    }
    
    for(i = 0; i < SUBTHREADNUM; i++)
    {
        pthread_join(thread[i], NULL);
    }
*/    
    int sockfd, len;
    SSL *ssl;
    //创建一个 socket 用于 tcp 通信
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket");
        SSL_CTX_free(ctx);
        return;
    }
    //printf("socket created!\n");
    
    //连接服务器
    if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
    {
        perror("Connect ");
        close(sockfd);
        SSL_CTX_free(ctx);
        return;
    }
    //printf("server connected!\n");
    //基于 ctx 产生一个新的 SSL
    ssl = SSL_new(ctx);
    if(thread_id >= threads / 2)
    {
        SSL_free(ssl);
        ssl = SSL_new(ctx);
    }
    SSL_set_fd(ssl, sockfd);
    //建立 SSL 连接
    if (SSL_connect(ssl) == -1)
    {
        //ERR_print_errors_fp(stderr);
        perror("SSL connect");
        SSL_free(ssl);
        close(sockfd);
        SSL_CTX_free(ctx);
        return;
    }
    else 
    {
        if(debug)
        {
            printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
        }
    }

    u_int64_t count = 0;
    u_int64_t starttime, endtime;
    starttime = apiTimeUs();
    while ((volatile int)shared_region->stop == 0)
    {
        len = SSL_write(ssl, buffer, strlen(buffer));
        if (len < 0)
        {
            printf("消息发送失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
            break;
        }
        else
        {
            count++;
            //printf("消息'%s'发送成功,共发送了%d个字节!\n", buffer, len);
        }
    }
    endtime = apiTimeUs();
    // 关闭连接
    //SSL_shutdown(ssl);
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);
    //业务处理结束
/*
    u_int64_t starttime, endtime;
    min_max_times(SUBTHREADNUM, subthread_region.starttime, subthread_region.endtime, &starttime, &endtime);
    u_int64_t count = 0;
    for(i = 0; i < SUBTHREADNUM; i++)
    {
        count += subthread_region.count[i];
    }
*/
    shared_region->count[thread_id] = count;
    shared_region->t1[thread_id] = starttime;
    shared_region->t2[thread_id] = endtime;
    sync();
}


void fullTest()
{
    int sockfd, len;
    SSL *ssl;
    shared_region->ready[thread_id] = 1;
    sync();
    while ((volatile int)shared_region->start == 0);
    
    u_int64_t count = 0;
    u_int64_t starttime, endtime;
    starttime = apiTimeUs();
    while ((volatile int)shared_region->stop == 0)
    {
        //创建一个 socket 用于 tcp 通信
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            perror("Socket");
            break;
        }
        //printf("socket created!\n");
        
        //连接服务器
        if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
        {
            perror("Connect ");
            close(sockfd);
            break;
        }
        //printf("server connected!\n");

        //基于 ctx 产生一个新的 SSL
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, sockfd);
        //建立 SSL 连接
        if (SSL_connect(ssl) == -1)
        {
            perror("SSL connect");
            SSL_free(ssl);
            close(sockfd);
            break;
        }
        else 
        {
            len = SSL_write(ssl, buffer, strlen(buffer));
            if (len < 0)
            {
                printf("消息发送失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
                SSL_free(ssl);
                close(sockfd);
                break;
            }
            else
            {
                count++;
                //printf("消息'%s'发送成功,共发送了%d个字节!\n", buffer, len);
            }
            if(debug)
            {
                if(count == 1)
                {
                    printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
                }
            }
        }
        // 关闭连接
        //SSL_shutdown(ssl);
        SSL_free(ssl);
        close(sockfd);
    }
    endtime = apiTimeUs();
    SSL_CTX_free(ctx);
    
    shared_region->count[thread_id] = count;
    shared_region->t1[thread_id] = starttime;
    shared_region->t2[thread_id] = endtime;
    sync();
}

void apacheTest()
{
    int sockfd, len;
    SSL *ssl;
    shared_region->ready[thread_id] = 1;
    sync();
    while ((volatile int)shared_region->start == 0);
    
    u_int64_t count = 0;
    u_int64_t starttime, endtime;
    starttime = apiTimeUs();
    char readBuff[MAXBUF] = {0};
    char writeData[200] = {0};
    sprintf(writeData, "%s%s%s", "GET /index.html HTTP/1.1\r\nHost: ", ip, "\r\nConnection: Close\r\n");
    while ((volatile int)shared_region->stop == 0)
    {
        //创建一个 socket 用于 tcp 通信
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            perror("Socket");
            break;
        }
        //printf("socket created!\n");
        
        //连接服务器
        if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)
        {
            perror("Connect ");
            close(sockfd);
            break;
        }
        //printf("server connected!\n");

        //基于 ctx 产生一个新的 SSL
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, sockfd);
        //建立 SSL 连接
        if (SSL_connect(ssl) == -1)
        {
            perror("SSL connect");
            SSL_free(ssl);
            close(sockfd);
            break;
        }
        else 
        {
            len = SSL_write(ssl, writeData, strlen(writeData));
            if (len < 0)
            {
                printf("消息发送失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
                SSL_free(ssl);
                close(sockfd);
                break;
            }
            else
            {
                count++;
                printf("消息'%s'发送成功,共发送了%d个字节!\n", readBuff, len);
            }
            memset(readBuff, 0 , MAXBUF);
            len = SSL_read(ssl, readBuff, MAXBUF);
            if(len < 0)
            {
                printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
                SSL_free(ssl);
                close(sockfd);
                break;
            }
            if(debug)
            {
                if(count == 1)
                {
                    printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
                    printf("The Apache data: %s\n", readBuff);
                }
            }
        }
        // 关闭连接
        //SSL_shutdown(ssl);
        SSL_free(ssl);
        close(sockfd);
    }
    endtime = apiTimeUs();
    SSL_CTX_free(ctx);
    
    shared_region->count[thread_id] = count;
    shared_region->t1[thread_id] = starttime;
    shared_region->t2[thread_id] = endtime;
    sync();
}

/**
 * 获取总的CPU利用率
*/
int getCpuTotalUseRatio()
{
    struct cpuinfo oldinfo;
    struct cpuinfo newinfo;
    getCpuInfo(&oldinfo);
    sleep(1);
    getCpuInfo(&newinfo);
    calCpuUseRatio(&oldinfo, &newinfo);
}

/**
 * 计算CPU利用率
*/
void calCpuUseRatio (struct cpuinfo *old, struct cpuinfo *new)
{
    double oldTotal, newTotal, total, idle, user, system, softirq, irq;
    float totalRatio, userRatio, systemRatio, softirqRatio, irqRatio;
    oldTotal = (double)(old->user + old->nice + old->system + old->idle + old->iowait +
                        old->irq + old->softirq + old->stealstolen + old->guest);
    newTotal = (double)(new->user + new->nice + new->system + new->idle + new->iowait +
                        new->irq + new->softirq + new->stealstolen + new->guest);
                        
    total = newTotal - oldTotal;
    idle  = new->idle - old->idle;
    user = new->user - old->user;
    system = new->system - old->system;
    softirq = new->softirq - old->softirq;
    irq = new->irq - old->irq;
    
    //CPU利用率
    totalRatio = (total - idle) / total;
    //用户空间CPU利用率
    userRatio = user / total;
    //内核空间CPU利用率
    systemRatio = system / total;
    //软中断CPU利用率
    softirqRatio = softirq / total;
    //硬中断CPU利用率
    irqRatio = irq / total;
    //printf("total:%f, idle:%f, new->idle:%u, old->idle:%u\n", total, idle, new->idle, old->idle);
    printf("总的CPU利用率为:%f(%f + %f + %f + %f)\n", totalRatio, userRatio, systemRatio, softirqRatio, irqRatio);
}

/**
 * 获取当前CPU信息
*/
void getCpuInfo (struct cpuinfo *cpu)
{
    FILE *fd;
    char buff[1024];
    fd = fopen ("/proc/stat", "r");
    fgets (buff, sizeof(buff), fd);
    sscanf (buff, "%s  %u %u %u %u %u %u %u %u %u", &cpu->name, &cpu->user, &cpu->nice, &cpu->system, 
            &cpu->idle,&cpu->iowait, &cpu->irq, &cpu->softirq, &cpu->stealstolen, &cpu->guest);
    printf ("%s %u %u %u %u %u %u %u %u %u\n", cpu->name, cpu->user, cpu->nice, cpu->system, 
            cpu->idle, cpu->iowait, cpu->irq, cpu->softirq, cpu->stealstolen, cpu->guest);
    fclose(fd);
}

server.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/mman.h>

#define SUBTHREADNUM 2
#define MAX_THREADS 100

int pkgSize = 1024;
int threads = 10;
int mode = 0;    //0-handshake 1-throughput
int port = 8701;

void handshakeTest();
void throughputTest();

SSL_CTX *ctx;
char *buffer;
int sockfd;
int debug = 0;
int thread_id = 0;
int pid[100];
int showTitle = 1;
int times = 10;

struct cpuinfo
{
    char name[20];
    unsigned int user;
    unsigned int nice;
    unsigned int system;
    unsigned int idle;
    unsigned int iowait;
    unsigned int irq;
    unsigned int softirq;
    unsigned int stealstolen;
    unsigned int guest;
};

void getCpuInfo (struct cpuinfo *cpu);
void calCpuUseRatio (struct cpuinfo *old, struct cpuinfo *new);
int getCpuTotalUseRatio();

struct shm_layout
{
    int ready[MAX_THREADS];
    int done[MAX_THREADS];
    int failCount[MAX_THREADS];
};

struct shm_layout *shared_region = NULL;
void usage()
{
    printf("Usage: Client \n\
            -p   Port (8701)\n\
            -s   Package Size (1024)\n\
            -l   Threads (10)\n\
            -m   Type (0-handshake 1-throughput default 0)\n\
            -d   Debug Info\n\
            -t   Time\n\
            -h   Help\n");
    exit(-1);
}

int main(int argc, char **argv)
{
    char options[] = "a:s:p:m:l:t:hde";
    int opt;
    while((opt = getopt(argc, argv, options)) != -1)
    {
        switch(opt)
        {
            case 's':
                pkgSize = atoi(optarg);
                //printf("pkgSize:%d\n", pkgSize);
                break;
            case 'l':
                threads = atoi(optarg);
                //printf("threads:%d\n", threads);
                break;
            case 'p':
                port = atoi(optarg);
                //printf("port:%d\n", port);
                break;
            case 'm':
                mode = atoi(optarg);
                //printf("type:%d\n", mode);
                break;
            case 'd':
                debug = 1;
                break;
            case 't':
                times = atoi(optarg);
            case 'e':
                showTitle = 0;
                break;
            case 'h':
            default:
                usage();
                break;
        }
    }
    if(showTitle)
    {
        if(mode == 0)
        {
            printf("------------------- Handshake Test -------------------\n");
        } 
        else if(mode == 1)
        {
            printf("------------------- Throughput Test -------------------\n");
        }
        printf("Server Port        Thread Number        Package Size\n");
    }
    printf("    %-20d %-20d %-18d\n", port, threads, pkgSize);
    
    shared_region = mmap(NULL, sizeof(struct shm_layout), PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
    if(shared_region == MAP_FAILED)
    {
        printf("\n ERROR mapping \n");
        exit(1);
    }
    memset(shared_region, 0, sizeof(struct shm_layout));
    
    struct sockaddr_in my_addr;
    unsigned int lisnum;

    lisnum = 20;

    buffer = malloc(pkgSize + 1);
    memset(buffer, 0 , pkgSize + 1);
    
    //SSL 库初始化
    SSL_library_init();
    //载入所有 SSL 算法
    OpenSSL_add_all_algorithms();
    //载入所有 SSL 错误消息
    SSL_load_error_strings();
    //以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text
    ctx = SSL_CTX_new(SSLv3_server_method());
    //也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准
    if (ctx == NULL)
    {
        printf("SSLContext failed!\n");
        exit(1);
    }
    //载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥
    if (SSL_CTX_use_certificate_file(ctx, "cacert.pem", SSL_FILETYPE_PEM) <= 0)
    {
        printf("Certificate load failed!\n");
        exit(1);
    }
    //载入用户私钥
    if (SSL_CTX_use_PrivateKey_file(ctx, "privkey.pem", SSL_FILETYPE_PEM) <= 0)
    {
        printf("PrivateKey load failed!\n");
        exit(1);
    }
    //检查用户私钥是否正确
    if (!SSL_CTX_check_private_key(ctx))
    {
        printf("PrivateKey check failed!\n");
        exit(1);
    }

    //开启一个 socket 监听
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket");
        exit(1);
    }
    else
    {
        if(debug)
        {
            printf("socket created\n");
        }
    }

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = PF_INET;
    my_addr.sin_port = htons(port);
    my_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1)
    {
        perror("bind");
        exit(1);
    }
    else
    {
        if(debug)
        {
            printf("binded\n");
        }
    }    

    if (listen(sockfd, lisnum) == -1)
    {
        perror("listen");
        exit(1);
    }
    else
    {
        if(debug)
        {
            printf("begin listen\n");
        }
    }
    
    int i;
    for(i = 0; i < threads; i++)
    {
        int kid = fork();
        if(kid < 0)
        {
            printf("Fork failed, Failed to create a new thread\n");
        }
        if(kid == 0)
        {
            thread_id = i;
            if(mode == 0)
            {
                handshakeTest();
            }
            else if(mode == 1)
            {
                throughputTest();
            }
            shared_region->done[thread_id] = 1;
            exit(0);
        }
        else
        {
            pid[i] = kid;
        }
    }
    
    for(i = 0;i < threads; i++)
    {
        while((volatile int)shared_region->ready[i] == 0)
        {
            usleep(10);
        }
    }
    
    getCpuTotalUseRatio();
    
    for(i = 0;i < threads; i++)
    {
        while((volatile int)shared_region->done[i] == 0)
        {
            usleep(1000);
        }
    }
    
    int total_fail_count = 0;
    for(i = 0;i < threads; i++)
    {
        total_fail_count += shared_region->failCount[i];
    }
    if(total_fail_count != threads)
    {
        printf("-------------------------------- Warning: failed count is %d --------------------------------\n", total_fail_count);
    }
    // 关闭监听的 socket
    close(sockfd);
}

void handshakeTest()
{
    SSL *ssl;
    int new_fd;
    int i = 0;
    int count = 0;
    while(1)
    {
        //等待客户端连上来
        if ((new_fd = accept(sockfd, NULL, NULL)) == -1)
        {
            if(count == 0)
            {
                shared_region->ready[thread_id] = 1;
                sync();
            }
            perror("accept");
            exit(errno);
        }
        else
        {
            //printf("Accepted success!\n");
        }
        //基于 ctx 产生一个新的 SSL
        ssl = SSL_new(ctx);
        if(count % 2 == 0)
        {
            SSL_free(ssl);
            ssl = SSL_new(ctx);
        }
        //将连接用户的 socket 加入到 SSL
        SSL_set_fd(ssl, new_fd);
        //建立 SSL 连接
        if (SSL_accept(ssl) == -1)
        {
            perror("accept");
            SSL_free(ssl);
            close(new_fd);
            break;
        }
        count++;
        //SSL_shutdown(ssl);
        //释放 SSL
        SSL_shutdown(ssl);
        SSL_free(ssl);
        //关闭 socket
        close(new_fd);
    }
    SSL_CTX_free(ctx);
}

void *createThread(void *arg)
{
    SSL *ssl;
    int new_fd;
    int len;
    /* 等待客户端连上来 */
    if ((new_fd = accept(sockfd, NULL, NULL)) == -1)
    {
        perror("accept");
        exit(errno);
    } 
    else
    {
        if(debug)
        {
            printf("Accepted success!\n");
        }
    }

    //基于 ctx 产生一个新的 SSL
    ssl = SSL_new(ctx);
    //将连接用户的 socket 加入到 SSL
    SSL_set_fd(ssl, new_fd);
    //建立 SSL 连接
    if (SSL_accept(ssl) == -1)
    {
        perror("accept");
        close(new_fd);
        exit(0);
    }
    int i = 0;
    while(1)
    {
        bzero(buffer, pkgSize + 1);
        //接收客户端的消息
        len = SSL_read(ssl, buffer, pkgSize);
        if (len > 0)
        {
            if(debug)
            {
                i++;
                if(i == 1)
                {
                    printf("接收消息成功:'%s',共%d个字节的数据\n", buffer, len);
                }
            }
        }
        else
        {
            printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
            break;
        }
    }
    //SSL_shutdown(ssl);
    //释放 SSL
    SSL_free(ssl);
    //关闭 socket
    close(new_fd);
    return NULL;
}

void throughputTest()
{
/*
    pthread_t thread[SUBTHREADNUM];
    int i;
    for(i = 0; i < SUBTHREADNUM; i++)
    {
        if(pthread_create(&thread[i], NULL, createThread, NULL) != 0)//创建子线程
        {
            perror("pthread_create");
            break;
        }
    }
    
    for(i = 0; i < SUBTHREADNUM; i++)
    {
        pthread_join(thread[i], NULL);
    }
*/
    SSL *ssl;
    int new_fd;
    int len;
    /* 等待客户端连上来 */
    if ((new_fd = accept(sockfd, NULL, NULL)) == -1)
    {
        perror("accept");
        exit(errno);
    } 
    else
    {
        if(debug)
        {
            printf("Accepted success!\n");
        }
    }
    shared_region->ready[thread_id] = 1;
    sync();
    //基于 ctx 产生一个新的 SSL
    ssl = SSL_new(ctx);
    if(thread_id >= threads / 2)
    {
        SSL_free(ssl);
        ssl = SSL_new(ctx);
    }
    //将连接用户的 socket 加入到 SSL
    SSL_set_fd(ssl, new_fd);
    //建立 SSL 连接
    if (SSL_accept(ssl) == -1)
    {
        perror("accept");
        close(new_fd);
        exit(0);
    }
    int i = 0;
    while(1)
    {
        bzero(buffer, pkgSize + 1);
        //接收客户端的消息
        len = SSL_read(ssl, buffer, pkgSize);
        if (len > 0)
        {
            if(debug)
            {
                i++;
                if(i == 1)
                {
                    printf("接收消息成功:'%s',共%d个字节的数据\n", buffer, len);
                }
            }
        }
        else
        {
            if(debug)
            {
                printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
            }
            shared_region->failCount[thread_id]++;
            break;
        }
    }
    sync();
    //SSL_shutdown(ssl);
    //释放 SSL
    SSL_free(ssl);
    //关闭 socket
    close(new_fd);
    SSL_CTX_free(ctx);
}

/**
 * 获取总的CPU利用率
*/
int getCpuTotalUseRatio()
{
    struct cpuinfo oldinfo;
    struct cpuinfo newinfo;
    getCpuInfo(&oldinfo);
    sleep(times - 1);
    getCpuInfo(&newinfo);
    calCpuUseRatio(&oldinfo, &newinfo);
}

/**
 * 计算CPU利用率
*/
void calCpuUseRatio (struct cpuinfo *old, struct cpuinfo *new)
{
    double oldTotal, newTotal, total, idle, user, system, softirq, irq;
    float totalRatio, userRatio, systemRatio, softirqRatio, irqRatio;
    oldTotal = (double)(old->user + old->nice + old->system + old->idle + old->iowait +
                        old->irq + old->softirq + old->stealstolen + old->guest);
    newTotal = (double)(new->user + new->nice + new->system + new->idle + new->iowait +
                        new->irq + new->softirq + new->stealstolen + new->guest);
                        
    total = newTotal - oldTotal;
    idle  = new->idle - old->idle;
    user = new->user - old->user;
    system = new->system - old->system;
    softirq = new->softirq - old->softirq;
    irq = new->irq - old->irq;
    
    //CPU利用率
    totalRatio = (total - idle) / total;
    //用户空间CPU利用率
    userRatio = user / total;
    //内核空间CPU利用率
    systemRatio = system / total;
    //软中断CPU利用率
    softirqRatio = softirq / total;
    //硬中断CPU利用率
    irqRatio = irq / total;
    //printf("total:%f, idle:%f, new->idle:%u, old->idle:%u\n", total, idle, new->idle, old->idle);
    printf("%f(%f + %f + %f + %f)\n", totalRatio, userRatio, systemRatio, softirqRatio, irqRatio);
}

/**
 * 获取当前CPU信息
*/
void getCpuInfo (struct cpuinfo *cpu)
{
    FILE *fd;
    char buff[1024];
    fd = fopen ("/proc/stat", "r");
    fgets (buff, sizeof(buff), fd);
    sscanf (buff, "%s  %u %u %u %u %u %u %u %u %u", &cpu->name, &cpu->user, &cpu->nice, &cpu->system, 
            &cpu->idle,&cpu->iowait, &cpu->irq, &cpu->softirq, &cpu->stealstolen, &cpu->guest);
    //printf ("%s %u %u %u %u %u %u %u %u %u\n", cpu->name, cpu->user, cpu->nice, cpu->system, 
            //cpu->idle, cpu->iowait, cpu->irq, cpu->softirq, cpu->stealstolen, cpu->guest);
    fclose(fd);
}

Makefile

CIPHER    = AES128-SHA      #AES128-SHA AES256-SHA RC4-SHA RC4-MD5
PKT_SIZES = 256 512 1024 1500 2048
RSA       = RSA_CRT RSA_NOCRT MODEXP
HANDSHAKE = RSASERVERFULL
NUM_THREADS      = 40       #MAX 100
NUM_THREADSHS    = 60       #MAX 100
NB_TEST_DURATION = 5 
HANDSHAKEIP      = 168.1.1.10
THROUGHPUTIP     = 169.1.1.10
TIME             = 10
LOOP             = 1 2 3 4 5 6
PORT             = 8701

CFLAGS = -I/usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto -ldl
CC = gcc
OBJS_SERVER = server.o
OBJS_CLIENT = client.o

all:server client

server: $(OBJS_SERVER)
	$(CC) -o $@ $^ ${CFLAGS}
client: $(OBJS_CLIENT)
	$(CC) -o $@ $^ ${CFLAGS}
	
handshake_client:
	for pktsize in ${PKT_SIZES}; do \
	./client -a ${THROUGHPUTIP} -l ${NUM_THREADSHS} -s $$pktsize -c AES128-SHA -t ${TIME};\
	done
throughput_AES128-SHA:
	@echo "------------------------------------- Throughput Test -------------------------------------";
	@echo "Server IP        Server Port        Thread Number        Times        Cipher        Version";
	@echo "${THROUGHPUTIP}            ${PORT}                ${NUM_THREADS}       ${TIME}        AES128-SHA       SSLv3";
	@echo "               Package Size(Bytes)        Operations        Throughtput(Mbps)";
	for pktsize in ${PKT_SIZES}; do \
	./client -m 1 -a ${THROUGHPUTIP} -l ${NUM_THREADS} -s $$pktsize -c AES128-SHA -t ${TIME} -e;\
	done
throughput_AES256-SHA:
	@echo "-------------------------------------------------------------------------------------------";
	@echo "Server IP        Server Port        Thread Number        Times        Cipher        Version";
	@echo "${THROUGHPUTIP}            ${PORT}                ${NUM_THREADS}       ${TIME}        AES256-SHA       SSLv3";
	@echo "               Package Size(Bytes)        Operations        Throughtput(Mbps)";
	for pktsize in ${PKT_SIZES}; do \
	./client -m 1 -a ${THROUGHPUTIP} -l ${NUM_THREADS} -s $$pktsize -c AES256-SHA -t ${TIME} -e;\
	done
throughput_RC4-SHA:
	@echo "-------------------------------------------------------------------------------------------";
	@echo "Server IP        Server Port        Thread Number        Times        Cipher        Version";
	@echo "${THROUGHPUTIP}            ${PORT}                ${NUM_THREADS}       ${TIME}          RC4-SHA         SSLv3";
	@echo "               Package Size(Bytes)        Operations        Throughtput(Mbps)";
	for pktsize in ${PKT_SIZES}; do \
	./client -m 1 -a ${THROUGHPUTIP} -l ${NUM_THREADS} -s $$pktsize -c RC4-SHA -t ${TIME} -e;\
	done
throughput_RC4-MD5:
	@echo "-------------------------------------------------------------------------------------------";
	@echo "Server IP        Server Port        Thread Number        Times        Cipher        Version";
	@echo "${THROUGHPUTIP}            ${PORT}                ${NUM_THREADS}       ${TIME}          RC4-MD5       SSLv3";
	@echo "               Package Size(Bytes)        Operations        Throughtput(Mbps)";
	for pktsize in ${PKT_SIZES}; do \
	./client -m 1 -a ${THROUGHPUTIP} -l ${NUM_THREADS} -s $$pktsize -c RC4-MD5 -t ${TIME} -e;\
	done
throughput_DES-CBC-SHA:
	@echo "-------------------------------------------------------------------------------------------";
	@echo "Server IP        Server Port        Thread Number        Times        Cipher        Version";
	@echo "${THROUGHPUTIP}            ${PORT}                ${NUM_THREADS}       ${TIME}       DES-CBC-SHA       SSLv3";
	@echo "               Package Size(Bytes)        Operations        Throughtput(Mbps)";
	for pktsize in ${PKT_SIZES}; do \
	./client -m 1 -a ${THROUGHPUTIP} -l ${NUM_THREADS} -s $$pktsize -c DES-CBC-SHA -t ${TIME} -e;\
	done
throughput_DES-CBC3-SHA:
	@echo "-------------------------------------------------------------------------------------------";
	@echo "Server IP        Server Port        Thread Number        Times        Cipher        Version";
	@echo "${THROUGHPUTIP}            ${PORT}                ${NUM_THREADS}       ${TIME}       DES-CBC3-SHA      SSLv3";
	@echo "               Package Size(Bytes)        Operations        Throughtput(Mbps)";
	for pktsize in ${PKT_SIZES}; do \
	./client -m 1 -a ${THROUGHPUTIP} -l ${NUM_THREADS} -s $$pktsize -c DES-CBC3-SHA -t ${TIME} -e;\
	done
handshake_server:
	./server -l ${NUM_THREADSHS};
throughput_server:
	@echo "------------------ Throughput Test ------------------";
	@echo "Server Port        Thread Number        Package Size";
	for var in ${LOOP}; do \
		for pktsize in ${PKT_SIZES}; do \
		./server -m 1 -l ${NUM_THREADS} -s $$pktsize -e;\
		done \
	done

run_client: throughput_AES128-SHA throughput_AES256-SHA throughput_RC4-SHA throughput_RC4-MD5 throughput_DES-CBC-SHA throughput_DES-CBC3-SHA handshake_client
run_server: throughput_server handshake_server

clean:
	rm -f *.o server client

make_key.sh

#!/bin/sh
openssl genrsa -out privkey.pem 2048
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值