Hello, I have some question: http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html What part is global, what part need be do by connexion? On that's: https://github.com/alphaonex86/CatchChallenger/blob/master/tools/epoll-with-buffer/main.cpp I have edited it to try do simple echo server. The handshake work, but no the echo (don't read any thing). I try do a sample how do epoll server with SSL support (not found on internet). And remake this graphic, and comment the code to match with this graphic. And into C++... I need too maximum of performance (no client cert), non blocking ops.
Thanks for your help. -- alpha_one_x86 <alpha_one_...@first-world.info> Main developer of Ultracopier, Esourcing and server management IT, OS, technologies, security and business department
#include <sys/epoll.h> #include <errno.h> #include <iostream> #include <list> #include <sys/socket.h> #include <netdb.h> #include <openssl/err.h> #include <openssl/rand.h> #include <openssl/ssl.h> #include "Client.h" #include "Socket.h" #include "Server.h" #include "Epoll.h" #include "Timer.h" #include "TimerDisplayEventBySeconds.h" #define MAXEVENTS 512 #define MAXCLIENT 6000 SSL_CTX* InitServerCTX(void) { OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ SSL_load_error_strings(); /* load all error messages */ const SSL_METHOD *method = TLSv1_2_server_method(); /* create new server-method instance */ SSL_CTX *ctx = SSL_CTX_new(method); /* create new context from method */ if(ctx == NULL) { ERR_print_errors_fp(stderr); abort(); } return ctx; } void LoadCertificates(SSL_CTX* ctx, const char* CertFile, const char* KeyFile) { SSL_CTX_set_verify(ctx,SSL_VERIFY_NONE,NULL); SSL_CTX_load_verify_locations(ctx,"/home/user/Desktop/CatchChallenger/test/openssl-server/cacert.pem",NULL); /* set the local certificate from CertFile */ if(SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM)<=0) { ERR_print_errors_fp(stderr); abort(); } /* set the private key from KeyFile (may be the same as CertFile) */ if(SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM)<=0) { ERR_print_errors_fp(stderr); abort(); } /* verify private key */ if(!SSL_CTX_check_private_key(ctx)) { fprintf(stderr, "Private key does not match the public certificate\n"); abort(); } } int main(int argc, char *argv[]) { SSL_library_init(); /* load encryption & hash algorithms for SSL */ SSL_load_error_strings(); /* load the error strings for good error reporting */ SSL_CTX *ctx = InitServerCTX(); /* initialize SSL */ LoadCertificates(ctx, "/home/user/Desktop/CatchChallenger/test/openssl-server/server.crt", "/home/user/Desktop/CatchChallenger/test/openssl-server/server.key"); /* load certs */ SSL *ssl = SSL_new(ctx); if(argc != 2) { fprintf(stderr, "Usage: %s [port]\n", argv[0]); exit(EXIT_FAILURE); } if(!Epoll::epoll.init()) abort(); Server server; if(!server.tryListen(argv[1])) abort(); TimerDisplayEventBySeconds timerDisplayEventBySeconds; if(!timerDisplayEventBySeconds.init()) abort(); char buf[512]; /* Buffer where events are returned */ epoll_event events[MAXEVENTS]; Client* clients[MAXCLIENT]; int clientListSize=0; /* The event loop */ int number_of_events, i; while(1) { number_of_events = Epoll::epoll.wait(events, MAXEVENTS); for(i = 0; i < number_of_events; i++) { switch(static_cast<BaseClassSwitch *>(events[i].data.ptr)->getType()) { case BaseClassSwitch::Type::Server: { if((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN) && !(events[i].events & EPOLLOUT))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf(stderr, "server epoll error\n"); continue; } /* We have a notification on the listening socket, which means one or more incoming connections. */ while(1) { if(clientListSize>=MAXCLIENT) break; sockaddr in_addr; socklen_t in_len = sizeof(in_addr); const int &infd = server.accept(&in_addr, &in_len); if(infd == -1) { if((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* We have processed all incoming connections. */ break; } else { perror("accept"); break; } } BIO* bioIn = BIO_new(BIO_s_mem()); BIO* bioOut = BIO_new(BIO_s_mem()); SSL_set_bio(ssl, bioIn, bioOut); int err = SSL_accept(ssl); //just for informations { char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; const int &s = getnameinfo(&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV); if(s == 0) printf("Accepted connection on descriptor %d (host=%s, port=%s)\n", infd, hbuf, sbuf); } /* Make the incoming socket non-blocking and add it to the list of fds to monitor. */ Client *client=new Client(); client->infd=infd; client->bioIn=bioIn; client->bioOut=bioOut; clients[clientListSize]=client; clientListSize++; int s = Socket::make_non_blocking(infd); if(s == -1) abort(); epoll_event event; event.data.ptr = client; event.events = EPOLLIN | EPOLLET | EPOLLOUT; s = Epoll::epoll.ctl(EPOLL_CTL_ADD, infd, &event); if(s == -1) { perror("epoll_ctl"); abort(); } } continue; } break; case BaseClassSwitch::Type::Client: { timerDisplayEventBySeconds.addCount(); Client *client=static_cast<Client *>(events[i].data.ptr); if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN) && !(events[i].events & EPOLLOUT))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf(stderr, "client epoll error\n"); client->close(); continue; } //ready to read if(events[i].events & EPOLLIN) { /* We have data on the fd waiting to be read. Read and display it. We must read whatever data is available completely, as we are running in edge-triggered mode and won't get a notification again for the same data. */ while (1) { const ssize_t &count = client->read(buf,sizeof(buf)); int bufferUsed = BIO_write(client->bioIn, buf, count); if(bufferUsed == -1 || bufferUsed == -2 || bufferUsed == 0) { // error } int bytesOut = SSL_read(ssl, (void*)buf, sizeof(buf)); if(bytesOut > 0) { } else { if (SSL_want_read(ssl)) { std::cout << "SSL_want_read" << std::endl; } else { int32_t ssl_error = SSL_get_error(ssl, bytesOut); switch (ssl_error) { case SSL_ERROR_NONE: printf("SSL_ERROR_NONE\n"); break; case SSL_ERROR_WANT_READ: printf("SSL_ERROR_WANT_READ\n"); break; case SSL_ERROR_WANT_WRITE: printf("SSL_ERROR_WANT_WRITE\n"); break; case SSL_ERROR_ZERO_RETURN: printf("SSL_ERROR_ZERO_RETURN\n"); break; default: break; } break; } if (!client->bHandShakeOver && SSL_is_init_finished(ssl)) { std::cout << "Handshake has been finished" << std::endl; client->bHandShakeOver = true; char cipdesc[128]; const SSL_CIPHER* sc = SSL_get_current_cipher(ssl); if (sc) std::cout << "encryption: " << SSL_CIPHER_description(sc, cipdesc, sizeof(cipdesc)) << std::endl; } } while (1) { // BIO_ctrl_pending() returns the number of bytes buffered in a BIO. size_t pending = BIO_ctrl_pending(client->bioOut); if (pending > 0) { std::cout << "BIO_ctrl_pending(bioOut) == " << pending << std::endl; // BIO_read() attempts to read len bytes from BIO b and places the data in buf. int bytesToSend = BIO_read(client->bioOut, (void*)buf, sizeof(buf) > pending ? pending : sizeof(buf)); if (bytesToSend > 0) { std::cout << "BIO_read(bioOut) == " << bytesToSend << std::endl; ssize_t nRet = client->write(buf, bytesToSend); if(nRet<0) { //bReplyOver = true; std::cerr << "send() - SOCKET_ERROR" << std::endl; } } else if (!BIO_should_retry(client->bioOut)) {// BIO_should_retry() is true if the call that produced this condition should then be retried at a later time. //reportError(ssl, bytesToSend); } } else { std::cout << "BIO_ctrl_pending(bioOut) == 0" << std::endl; break; } } /*if (bReplyOver) { std::cout << "post-reply" << std::endl; break; }*/ if(count>0) { //broadcast to all the client /*int index=0; while(index<clientListSize) { clients[index]->write(buf,count); index++; }*/ } else break; } } //ready to write if(events[i].events & EPOLLOUT) { client->flush(); } } break; case BaseClassSwitch::Type::Timer: static_cast<Timer *>(events[i].data.ptr)->exec(); break; default: fprintf(stderr, "unknown event\n"); break; } } } server.close(); return EXIT_SUCCESS; }
signature.asc
Description: This is a digitally signed message part.