server.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.8.0/modules/webservice/server.cpp $
00003   version : $LastChangedRevision: 1108 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2009-12-06 18:54:18 +0100 (Sun, 06 Dec 2009) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007 by Johan De Taeye                                    *
00010  *                                                                         *
00011  * This library is free software; you can redistribute it and/or modify it *
00012  * under the terms of the GNU Lesser General Public License as published   *
00013  * by the Free Software Foundation; either version 2.1 of the License, or  *
00014  * (at your option) any later version.                                     *
00015  *                                                                         *
00016  * This library is distributed in the hope that it will be useful,         *
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
00019  * General Public License for more details.                                *
00020  *                                                                         *
00021  * You should have received a copy of the GNU Lesser General Public        *
00022  * License along with this library; if not, write to the Free Software     *
00023  * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,*
00024  * USA                                                                     *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 /* The code in this file is copied from the gsoap manual, with only relatively
00029  * small changes.
00030  */
00031 
00032 #include "module.h"
00033 #include <pthread.h>
00034 
00035 namespace module_webservice
00036 {
00037 
00038 
00039 PyObject* CommandWebservice::pythonService(PyObject* self, PyObject* args)
00040 {
00041   Py_BEGIN_ALLOW_THREADS   // Free Python interpreter for other threads
00042   try {
00043     CommandWebservice().execute();  
00044   }
00045   catch (...)
00046   {
00047     Py_BLOCK_THREADS;
00048     PythonType::evalException();
00049     return NULL;
00050   }
00051   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00052   return Py_BuildValue("");
00053 }
00054 
00055 
00056 void CommandWebservice::execute()
00057 {
00058   // Initialize
00059   thread_data threadinfo[threads];
00060   struct soap soap;
00061   soap_init(&soap);
00062   SOAP_SOCKET mastersocket, slavesocket;
00063 
00064   // Bind to a port on the local machine.
00065   mastersocket = soap_bind(&soap, NULL, port, BACKLOG);
00066   if (!soap_valid_socket(mastersocket))
00067     throw RuntimeException("Can't bind to port " + port);
00068 
00069   // Creating execution threads in the pool
00070   pthread_mutex_init(&queue_cs, NULL);
00071   pthread_cond_init(&queue_cv, NULL);
00072   for (int i = 0; i < threads; i++)
00073   {
00074     threadinfo[i].master = this;
00075     threadinfo[i].index = i;
00076     threadinfo[i].soap_thr = soap_copy(&soap);
00077     pthread_create(&threadinfo[i].tid, NULL, (void*(*)(void*))process_queue, static_cast<void*>(&threadinfo[i]));
00078   }
00079 
00080   // Loop forever
00081   for (;;)
00082   {
00083     // Wait for incoming connection on the port
00084     slavesocket = soap_accept(&soap);
00085     if (!soap_valid_socket(slavesocket))
00086     {
00087       if (soap.errnum)
00088       {
00089         soap_print_fault(&soap, stderr);
00090         continue; // retry
00091       }
00092       else
00093       {
00094         logger << "Server timed out" << endl;
00095         break;
00096       }
00097     }
00098     logger << "Connection from " << ((soap.ip >> 24)&0xFF) << "."
00099       << ((soap.ip >> 16)&0xFF) << "." << ((soap.ip >> 8)&0xFF) << "."
00100       << (soap.ip&0xFF) << endl;
00101 
00102     // Loop until the request could be entered in the request queue
00103     while (enqueue(slavesocket) == SOAP_EOM)
00104       sleep(1);
00105   }
00106 
00107   // Send termination signal to all threads
00108   for (int i = 0; i < threads; i++)
00109   {
00110     // Put termination requests in the queue
00111     while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM)
00112       sleep(1);
00113   }
00114 
00115   // Wait for the threads to terminate
00116   for (int i = 0; i < threads; i++)
00117   {
00118     pthread_join(threadinfo[i].tid, NULL);
00119     soap_done(threadinfo[i].soap_thr);
00120     free(threadinfo[i].soap_thr);
00121   }
00122 
00123   // Cleaning up
00124   pthread_mutex_destroy(&queue_cs);
00125   pthread_cond_destroy(&queue_cv);
00126   soap_done(&soap);
00127 }
00128 
00129 
00130 void* CommandWebservice::process_queue(void *soap)
00131 {
00132    struct thread_data *mydata = (struct thread_data*)soap;
00133    // Loop forever
00134    for (;;)
00135    {
00136       // Pick a request from my master's queue
00137       mydata->soap_thr->socket = mydata->master->dequeue();
00138 
00139       // Break out of the loop if an invalid socket is put in the queue
00140       if (!soap_valid_socket(mydata->soap_thr->socket)) break;
00141 
00142       // Process the request
00143       soap_serve(mydata->soap_thr);
00144       soap_destroy(mydata->soap_thr);
00145       soap_end(mydata->soap_thr);
00146    }
00147    return NULL;
00148 }
00149 
00150 
00151 int CommandWebservice::enqueue(SOAP_SOCKET sock)
00152 {
00153    int status = SOAP_OK;
00154    int next;
00155    pthread_mutex_lock(&queue_cs);
00156    next = tail + 1;
00157    if (next >= MAX_QUEUE)
00158       next = 0;
00159    if (next == head)
00160       status = SOAP_EOM;
00161    else
00162    {
00163       queue[tail] = sock;
00164       tail = next;
00165    }
00166    pthread_cond_signal(&queue_cv);
00167    pthread_mutex_unlock(&queue_cs);
00168    return status;
00169 }
00170 
00171 
00172 SOAP_SOCKET CommandWebservice::dequeue()
00173 {
00174    SOAP_SOCKET sock;
00175    pthread_mutex_lock(&queue_cs);
00176    while (head == tail) pthread_cond_wait(&queue_cv, &queue_cs);
00177    sock = queue[head++];
00178    if (head >= MAX_QUEUE)
00179       head = 0;
00180    pthread_mutex_unlock(&queue_cs);
00181    return sock;
00182 }
00183 
00184 }