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 }