#include <stdio.h>
#include <curl/curl.h>
#include <unistd.h>

CURL *easy_handle=NULL;
CURLM *multi_handle = NULL;

void printTCPInfo(CURL *curl)
{
    char* rip = NULL;
    char* lip = NULL;
    long rport = -1;
    long lport = -1;
    curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &rip);
    curl_easy_getinfo(curl, CURLINFO_LOCAL_IP, &lip);
    curl_easy_getinfo(curl, CURLINFO_PRIMARY_PORT, &rport);
    curl_easy_getinfo(curl, CURLINFO_LOCAL_PORT, &lport);

    printf("lip:%s lport:%ld <---> rip:%s rport:%ld\n",lip?lip:"na", lport, rip?rip:"na", rport);
}


void performEasyRequest(const char* cUrl)
{

    CURLcode res;

    if (!easy_handle)
    {
        easy_handle = curl_easy_init();
        printf("curl handle init\n");
    }
    else
    {
        curl_easy_reset(easy_handle);
    }

    if (easy_handle)
    {
        printf("easy start----------------\n");
        printf("URL:%s\n",cUrl);

        char errorBuffer[CURL_ERROR_SIZE];
        errorBuffer[0] = '\0';

        curl_easy_setopt(easy_handle, CURLOPT_ERRORBUFFER , errorBuffer);


        curl_easy_setopt(easy_handle, CURLOPT_URL, cUrl);
        res = curl_easy_perform(easy_handle);
        printf("curl finished--------------------\n");

        printf("res:%d -> \"%s\" -> \"%s\" \n",res, curl_easy_strerror(res), errorBuffer);

        printTCPInfo(easy_handle);
        printf("easy end--------------------\n");
    }
}


void performMultiRequest(const char* cUrl)
{
    if (!multi_handle)
    {
        multi_handle = curl_multi_init();
    }

    if (!easy_handle)
    {
        easy_handle = curl_easy_init();
        printf("curl handle init\n");
    }
    else
    {
        curl_easy_reset(easy_handle);
    }

    printf("multi start----------------\n");
    printf("URL:%s\n",cUrl);

    int still_running;

    curl_easy_setopt(easy_handle, CURLOPT_URL, cUrl);

    curl_multi_add_handle(multi_handle, easy_handle);

    while (CURLM_CALL_MULTI_PERFORM ==
            curl_multi_perform(multi_handle, &still_running));

    while (still_running)
    {
        struct timeval timeout;
        int rc=1; /* select() return code */

        fd_set fdread;
        fd_set fdwrite;
        fd_set fdexcep;
        int maxfd;

        FD_ZERO(&fdread);
        FD_ZERO(&fdwrite);
        FD_ZERO(&fdexcep);

        /* set a suitable timeout to play around with */
        timeout.tv_sec = 2;
        timeout.tv_usec = 0;

        /* get file descriptors from the transfers */
        curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
        /* In a real-world program you OF COURSE check the return code of the
                function calls, *and* you make sure that maxfd is bigger than -1 so
                that the call to select() below makes sense! */

        //printf("select()\n");
        rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
        //printf("select() returns:%d\n",rc);

        switch (rc)
        {
        case -1:
            /* select error */
            still_running = 0;
            printf("select() returns error, this is badness\n");
            break;
        case 0:
            printf("select() timeout\n");
        default:
            /* timeout or readable/writable sockets */
            printf(".");
            fflush(NULL);
            while (CURLM_CALL_MULTI_PERFORM ==
                    curl_multi_perform(multi_handle, &still_running));
            break;
        }
    }//still running

    printf("curl finished--------------------\n");

    curl_multi_remove_handle(multi_handle, easy_handle);

    printTCPInfo(easy_handle);

    curl_easy_cleanup(easy_handle);
    easy_handle = 0;

    printf("multi end----------------\n");

}


int main(int argc, char* argv[])
{
    const char* cUrl= "127.0.0.1";
    if ( argc>1 )
    {
        cUrl=argv[1];
    }

//    performEasyRequest(cUrl);
//    performEasyRequest(cUrl);
    performMultiRequest(cUrl);
    performMultiRequest(cUrl);

    return 0;
}

