/* Handles a number of connections for a thread. * * data The thread data. */ static void *ThreadHandler(void *data) { int ret; socklen_t socketfd = -1; int efd; struct epoll_event event; struct epoll_event event_conn; struct epoll_event* events = NULL; ThreadData* threadData = (ThreadData*)data; #ifdef WOLFSSL_ASYNC_CRYPT WOLF_EVENT* wolfEvents[MAX_WOLF_EVENTS]; #endif /* Initialize wolfSSL and create a context object. */ if (WolfSSLCtx_Init(version, ourCert, ourKey, verifyCert, cipherList, &threadData->devId, &threadData->ctx) == -1) { exit(EXIT_FAILURE); } /* Allocate space for EPOLL events to be stored. */ events = (struct epoll_event*)malloc(EPOLL_NUM_EVENTS * sizeof(*events)); if (events == NULL) exit(EXIT_FAILURE); /* Create a socket and listen for a client. */ if (CreateSocketListen(port, numClients, &socketfd) == EXIT_FAILURE) exit(EXIT_FAILURE); /* Create an EPOLL file descriptor. */ efd = epoll_create1(0); if (efd == -1) { fprintf(stderr, "ERROR: failed to create epoll\n"); exit(EXIT_FAILURE); } /* Add the event for communications on listening socket. */ memset(&event, 0, sizeof(event)); event.events = EPOLLIN; event.data.ptr = NULL; ret = epoll_ctl(efd, EPOLL_CTL_ADD, socketfd, &event); if (ret == -1) { fprintf(stderr, "ERROR: failed to add event to epoll\n"); exit(EXIT_FAILURE); } threadData->accepting = 1; /* Keep handling clients until done. */ while (!SSLConn_Done(sslConnCtx)) { int n; int i; #ifdef WOLFSSL_ASYNC_CRYPT do { double diff, start = current_time(1); ret = wolfSSL_CTX_AsyncPoll(threadData->ctx, wolfEvents, MAX_WOLF_EVENTS, WOLF_POLL_FLAG_CHECK_HW, &n); diff = current_time(0) - start; pthread_mutex_lock(&sslConnMutex); sslConnCtx->asyncTime += diff; pthread_mutex_unlock(&sslConnMutex); for (i = 0; i < n; i++) { SSLConn* sslConn = threadData->sslConn; while (sslConn != NULL) { if (sslConn->ssl != wolfEvents[i]->context) { sslConn = sslConn->next; continue; } SSLConn_ReadWrite(sslConnCtx, threadData, sslConn); break; } } } while (n > 0); #endif SSLConn_FreeSSLConn(threadData); #ifdef WOLFSSL_ASYNC_CRYPT /* Look for events. */ n = epoll_wait(efd, events, EPOLL_NUM_EVENTS, 0); #else /* Wait a second for events. */ n = epoll_wait(efd, events, EPOLL_NUM_EVENTS, 1); #endif /* Process all returned events. */ for (i = 0; i < n; i++) { /* Error event on socket. */ if (!(events[i].events & EPOLLIN)) { if (events[i].data.ptr == NULL) { /* Not a client, therefore the listening connection. */ close(socketfd); socketfd = -1; } else { /* Client connection. */ SSLConn_Close(sslConnCtx, threadData, events[i].data.ptr); ret = epoll_ctl(efd, EPOLL_CTL_ADD, socketfd, &event); } } else if (events[i].data.ptr == NULL) { SSLConn* sslConn; /* Accept a new client on the listener. */ ret = SSLConn_Accept(threadData, threadData->ctx, socketfd, &sslConn); if (ret == EXIT_SUCCESS) { /* Set EPOLL to check for events on the new socket. */ memset(&event_conn, 0, sizeof(event_conn)); event_conn.events = EPOLLIN | EPOLLET; event_conn.data.ptr = sslConn; ret = epoll_ctl(efd, EPOLL_CTL_ADD, sslConn->sockfd, &event_conn); if (ret == -1) { fprintf(stderr, "ERROR: failed add event to epoll\n"); exit(EXIT_FAILURE); } } if (threadData->cnt == sslConnCtx->numConns) { /* Don't accept any more TCP connections. */ ret = epoll_ctl(efd, EPOLL_CTL_DEL, socketfd, &event); if (ret == -1) { fprintf(stderr, "ERROR: failed delete epoll event\n"); exit(EXIT_FAILURE); } threadData->accepting = 0; } } else { if (sslConnCtx->totalTime == 0) { pthread_mutex_lock(&sslConnMutex); if (sslConnCtx->totalTime == 0) sslConnCtx->totalTime = current_time(1); pthread_mutex_unlock(&sslConnMutex); } ret = SSLConn_ReadWrite(sslConnCtx, threadData, events[i].data.ptr); } } /* Accept more connections again up to the maximum concurrent. */ if (!threadData->accepting && threadData->cnt < sslConnCtx->numConns) { ret = epoll_ctl(efd, EPOLL_CTL_ADD, socketfd, &event); if (ret == -1) { fprintf(stderr, "ERROR: failed add event to epoll\n"); exit(EXIT_FAILURE); } threadData->accepting = 1; } } if (socketfd != -1) close(socketfd); free(events); return NULL; }
/* Main entry point for the program. * * argc The count of command line arguments. * argv The command line arguments. * returns 0 on success and 1 otherwise. */ int main(int argc, char* argv[]) { socklen_t socketfd = -1; int ch; WOLFSSL_CTX* ctx = NULL; SSLConn_CTX* sslConnCtx; word16 port = wolfSSLPort; int resumeSession = 0; char* cipherList = NULL; char* ourCert = CLI_CERT; char* ourKey = CLI_KEY; char* verifyCert = CA_CERT; int version = SERVER_DEFAULT_VERSION; int numConns = SSL_NUM_CONN; int numBytesRead = NUM_READ_BYTES; int numBytesWrite = NUM_WRITE_BYTES; int maxBytes = MAX_BYTES; int maxConns = MAX_CONNECTIONS; int i; /* Parse the command line arguments. */ while ((ch = mygetopt(argc, argv, OPTIONS)) != -1) { switch (ch) { /* Help with command line options. */ case '?': Usage(); exit(EXIT_SUCCESS); /* Port number to connect to. */ case 'p': port = (word16)atoi(myoptarg); break; /* Version of SSL/TLS to use. */ case 'v': version = atoi(myoptarg); if (version < 0 || version > 3) { Usage(); exit(MY_EX_USAGE); } break; /* List of cipher suites to use. */ case 'l': cipherList = myoptarg; break; /* File name of client certificate for client authentication. */ case 'c': ourCert = myoptarg; break; /* File name of client private key for client authentication. */ case 'k': ourKey = myoptarg; break; /* File name of server certificate/CA for peer verification. */ case 'A': verifyCert = myoptarg; break; /* Resume sessions. */ case 'r': resumeSession = 1; break; /* Number of connections to make. */ case 'n': maxConns = atoi(myoptarg); if (maxConns < 0 || maxConns > 1000000) { Usage(); exit(MY_EX_USAGE); } maxBytes = 0; break; /* Number of conncurrent connections to use. */ case 'N': numConns = atoi(myoptarg); if (numConns < 0 || numConns > 1000000) { Usage(); exit(MY_EX_USAGE); } break; /* Number of bytes to read each call. */ case 'R': numBytesRead = atoi(myoptarg); if (numBytesRead <= 0) { Usage(); exit(MY_EX_USAGE); } break; /* Number of bytes to write each call. */ case 'W': numBytesWrite = atoi(myoptarg); if (numBytesWrite <= 0) { Usage(); exit(MY_EX_USAGE); } break; /* Maximum number of read and write bytes (separate counts). */ case 'B': maxBytes = atoi(myoptarg); if (maxBytes <= 0) { Usage(); exit(MY_EX_USAGE); } maxConns = 0; break; /* Unrecognized command line argument. */ default: Usage(); exit(MY_EX_USAGE); } } #ifdef DEBUG_WOLFSSL wolfSSL_Debugging_ON(); #endif /* Initialize wolfSSL */ wolfSSL_Init(); /* Initialize wolfSSL and create a context object. */ if (WolfSSLCtx_Init(version, ourCert, ourKey, verifyCert, cipherList, &ctx) == EXIT_FAILURE) exit(EXIT_FAILURE); /* Create SSL/TLS connection data object. */ sslConnCtx = SSLConn_New(numConns, numBytesRead, numBytesWrite, maxConns, maxBytes, resumeSession); if (sslConnCtx == NULL) exit(EXIT_FAILURE); /* Keep handling connections until all done. */ for (i = 0; !SSLConn_Done(sslConnCtx); i = (i + 1) % numConns) { SSLConn* sslConn = &sslConnCtx->sslConn[i]; /* Perform close if in CLOSE state. */ if (sslConn->state == CLOSE) { if (sslConnCtx->numConnections == 0) { WOLFSSL_CIPHER* cipher; cipher = wolfSSL_get_current_cipher(sslConn->ssl); printf("SSL cipher suite is %s\n", wolfSSL_CIPHER_get_name(cipher)); } SSLConn_Close(sslConnCtx, sslConn); } /* Create TCP connection and connect if in INIT state. */ if ((sslConn->state == INIT) && ((sslConnCtx->maxConnections <= 0) || (sslConnCtx->numCreated < sslConnCtx->maxConnections))) { if (CreateSocketConnect(port, &socketfd) == EXIT_FAILURE) { printf("ERROR: failed to connect to server\n"); exit(EXIT_FAILURE); } SSLConn_Connect(sslConnCtx, ctx, socketfd, sslConn); } #ifdef WOLFSSL_ASYNC_CRYPT if (sslConn->err == 4) { int ret; double start; start = current_time(1); ret = wolfSSL_AsyncPoll(sslConn->ssl, WOLF_POLL_FLAG_CHECK_HW); sslConnCtx->asyncTime += current_time(0) - start; if (ret < 0) { printf("ERROR: failed in async polling\n"); break; } if (ret == 0) continue; } sslConn->err = 0; #endif /* Handle other SSL states. */ if (sslConnCtx->totalTime == 0) sslConnCtx->totalTime = current_time(1); if (SSLConn_ReadWrite(sslConnCtx, sslConn) == EXIT_FAILURE) { if (sslConnCtx->maxConnections > 0) sslConn->state = CLOSE; } } sslConnCtx->totalTime = current_time(0) - sslConnCtx->totalTime; SSLConn_PrintStats(sslConnCtx); SSLConn_Free(sslConnCtx); WolfSSLCtx_Final(ctx); wolfSSL_Cleanup(); exit(EXIT_SUCCESS); }