Disconnect Client connected to cgi application

266 views Asked by At

I have a simple C++ CGI Application that receives form data from client. The client is written in C# and uses WWWForm to send and receive data to the C++ CGI Application and everything seems to be working with one exception.

For example, when I send a registration form to the CGI Application, My CGI Application is able to receive the data but when I send an email to the email provided in the form, it makes the client to wait until the email is sent before it disconnects.

I want to process the data, disconnect the client then send the email because sending emails takes time and I want the server response to be fast.

How can I disconnect the client from the CGI Application? Currently right now, the only way the client disconnects is when the CGI Application closes or ends but is there a way to disconnect the client prematurelyso that it doesn't have to wait for the email to finish sending?

I did online research about this but didn't find any single solution to this.

2

There are 2 answers

3
Hauke S On BEST ANSWER

I wrote a very simple c++ cgi using CodeBlocks and MinGW.

All it does is that it creates a detached process and returns directly. It doesn't read any request. That will be left to you.

To get data to the new process you will probably have to write what you want to send into a file and then provide the path to that file to the new process via the commandline that is passed to CreateProcess.

I tested the cgi using Xampp. Please note that you will have to look into the Task Manager in order to check the process has been started as no window will open up.

#include <iostream>
#include "windows.h"

using namespace std;

int main()
{
    cout << "Content-type: text/html\n\n";
    cout << "<html><head></head><body>";

    cout << "Hello world! I'm starting a batch job";

    cout << "</body></html>" << endl;

    STARTUPINFO siStartupInfo = {sizeof(STARTUPINFO)};

    siStartupInfo.cb = sizeof(siStartupInfo);
    siStartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    siStartupInfo.wShowWindow = SW_HIDE;

    PROCESS_INFORMATION piProcessInfo;

    CreateProcess(NULL, (LPSTR)"\"D:\\Program Files (x86)\\CodeBlocks\\codeblocks.exe\" ",
    0, 0, false, CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW | DETACHED_PROCESS , 0, 0,
    &siStartupInfo, &piProcessInfo);

    cout << "I created a new process!";

    return 0;
}
6
B.R.W. On

Your CGI application is just a C/C++ program. With that in mind, if you already have the code that sends the email, just run it on another thread.

Depending on what you have configured on your project, you can use pthread or boost::thread.

Example of thread creation using using pthread:

#include <pthread.h>
#include <iostream>

typedef struct{
    // Sample parameters, use your own.
    std::string subject;
    std::string sender;
    std::string recipient;
    std::string message;
} EmailData;

void* do_send_mail(void* void_ptr)
{
    EmailData* data = (EmailData*)void_ptr;

    // your code that sends the email

    delete data;
    return NULL;
}

int main()
{
    // Thread handle
    pthread_t send_mail_thread;

    // Your email struct
    EmailData* email = new EmailData;

    email->subject = "Testing email.";
    email->recipient = "[email protected]";
    email->sender = "[email protected]";
    email->message = "You just won one billion dollars!";

    if(pthread_create(&send_mail_thread, NULL, do_send_mail, (void*)email)) {

        std::cout << "Failed to create thread that sends the email." << std::endl;
        return 1;

    }

    // Remove this "join" in your CGI application, it waits for the thread to
    // finish (which will make your client wait just like it does now)
    pthread_join(send_mail_thread, NULL);

    return 0;
}

Example of thread creation using using boost::thread:

#include <boost/thread.hpp>

typedef struct{
    // Sample parameters, use your own.
    std::string subject;
    std::string sender;
    std::string recipient;
    std::string message;
} EmailData;

void do_send_mail(EmailData& email)
{
    // your code that sends email here
}

int main(int argc, char* argv[])
{

    EmailData email;
    email.subject = "Testing email.";
    email.recipient = "[email protected]";
    email.sender = "[email protected]";
    email.message = "You just won one billion dollars!";

    boost::thread email_thread(boost::bind<void>(do_send_mail, email));

    // Remove this "join" in your CGI application, it waits for the thread to
    // finish (which will make your client wait just like it does now)
    email_thread.join();

    return 0;
}

Example of thread creation using using boost::thread (with lambda):

#include <boost/thread.hpp>

typedef struct{
    // Sample parameters, use your own.
    std::string subject;
    std::string sender;
    std::string recipient;
    std::string message;
} EmailData;

int main(int argc, char* argv[])
{

    EmailData email;
    email.subject = "Testing email.";
    email.recipient = "[email protected]";
    email.sender = "[email protected]";
    email.message = "You just won one billion dollars!";

    boost::thread email_thread(boost::bind<void>([](EmailData& email)->void{

        // your code that sends email here

    }, email));

    // Remove this "join" in your CGI application, it waits for the thread to
    // finish (which will make your client wait just like it does now)
    email_thread.join();

    return 0;
}