-- 
alpha_one_x86 <alpha_one_...@first-world.info>
Main developer of Ultracopier, Esourcing and server management
IT, OS, technologies, security and business department
--- Begin Message ---
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;
}

Attachment: signature.asc
Description: This is a digitally signed message part.


--- End Message ---

Reply via email to