server.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/tags/0.9.1/modules/webservice/server.cpp $
00003   version : $LastChangedRevision: 1656 $  $LastChangedBy: jdetaeye $
00004   date : $LastChangedDate: 2012-03-27 19:05:34 +0200 (Tue, 27 Mar 2012) $
00005  ***************************************************************************/
00006 
00007 /***************************************************************************
00008  *                                                                         *
00009  * Copyright (C) 2007-2012 by Johan De Taeye, frePPLe bvba                 *
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   {
00044     CommandWebservice().commit();
00045   }
00046   catch (...)
00047   {
00048     Py_BLOCK_THREADS;
00049     PythonType::evalException();
00050     return NULL;
00051   }
00052   Py_END_ALLOW_THREADS   // Reclaim Python interpreter
00053   return Py_BuildValue("");
00054 }
00055 
00056 
00057 void CommandWebservice::commit()
00058 {
00059   // Initialize
00060   thread_data threadinfo[threads];
00061   struct soap soap;
00062   soap_init(&soap);
00063   SOAP_SOCKET mastersocket, slavesocket;
00064 
00065   // Bind to a port on the local machine.
00066   mastersocket = soap_bind(&soap, NULL, port, BACKLOG);
00067   if (!soap_valid_socket(mastersocket))
00068     throw RuntimeException("Can't bind to port " + port);
00069 
00070   // Creating execution threads in the pool
00071   pthread_mutex_init(&queue_cs, NULL);
00072   pthread_cond_init(&queue_cv, NULL);
00073   for (int i = 0; i < threads; i++)
00074   {
00075     threadinfo[i].master = this;
00076     threadinfo[i].index = i;
00077     threadinfo[i].soap_thr = soap_copy(&soap);
00078     pthread_create(&threadinfo[i].tid, NULL, (void*(*)(void*))process_queue, static_cast<void*>(&threadinfo[i]));
00079   }
00080 
00081   // Loop forever
00082   for (;;)
00083   {
00084     // Wait for incoming connection on the port
00085     slavesocket = soap_accept(&soap);
00086     if (!soap_valid_socket(slavesocket))
00087     {
00088       if (soap.errnum)
00089       {
00090         soap_print_fault(&soap, stderr);
00091         continue; // retry
00092       }
00093       else
00094       {
00095         logger << "Server timed out" << endl;
00096         break;
00097       }
00098     }
00099     logger << "Connection from " << ((soap.ip >> 24)&0xFF) << "."
00100         << ((soap.ip >> 16)&0xFF) << "." << ((soap.ip >> 8)&0xFF) << "."
00101         << (soap.ip&0xFF) << endl;
00102 
00103     // Loop until the request could be entered in the request queue
00104     while (enqueue(slavesocket) == SOAP_EOM)
00105       sleep(1);
00106   }
00107 
00108   // Send termination signal to all threads
00109   for (int i = 0; i < threads; i++)
00110   {
00111     // Put termination requests in the queue
00112     while (enqueue(SOAP_INVALID_SOCKET) == SOAP_EOM)
00113       sleep(1);
00114   }
00115 
00116   // Wait for the threads to terminate
00117   for (int i = 0; i < threads; i++)
00118   {
00119     pthread_join(threadinfo[i].tid, NULL);
00120     soap_done(threadinfo[i].soap_thr);
00121     free(threadinfo[i].soap_thr);
00122   }
00123 
00124   // Cleaning up
00125   pthread_mutex_destroy(&queue_cs);
00126   pthread_cond_destroy(&queue_cv);
00127   soap_done(&soap);
00128 }
00129 
00130 
00131 void* CommandWebservice::process_queue(void *soap)
00132 {
00133   struct thread_data *mydata = (struct thread_data*)soap;
00134   // Loop forever
00135   for (;;)
00136   {
00137     // Pick a request from my master's queue
00138     mydata->soap_thr->socket = mydata->master->dequeue();
00139 
00140     // Break out of the loop if an invalid socket is put in the queue
00141     if (!soap_valid_socket(mydata->soap_thr->socket)) break;
00142 
00143     // Process the request
00144     soap_serve(mydata->soap_thr);
00145     soap_destroy(mydata->soap_thr);
00146     soap_end(mydata->soap_thr);
00147   }
00148   return NULL;
00149 }
00150 
00151 
00152 int CommandWebservice::enqueue(SOAP_SOCKET sock)
00153 {
00154   int status = SOAP_OK;
00155   int next;
00156   pthread_mutex_lock(&queue_cs);
00157   next = tail + 1;
00158   if (next >= MAX_QUEUE)
00159     next = 0;
00160   if (next == head)
00161     status = SOAP_EOM;
00162   else
00163   {
00164     queue[tail] = sock;
00165     tail = next;
00166   }
00167   pthread_cond_signal(&queue_cv);
00168   pthread_mutex_unlock(&queue_cs);
00169   return status;
00170 }
00171 
00172 
00173 SOAP_SOCKET CommandWebservice::dequeue()
00174 {
00175   SOAP_SOCKET sock;
00176   pthread_mutex_lock(&queue_cs);
00177   while (head == tail) pthread_cond_wait(&queue_cv, &queue_cs);
00178   sock = queue[head++];
00179   if (head >= MAX_QUEUE)
00180     head = 0;
00181   pthread_mutex_unlock(&queue_cs);
00182   return sock;
00183 }
00184 
00185 }

Documentation generated for frePPLe by  doxygen