server.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 file : $URL: https://frepple.svn.sourceforge.net/svnroot/frepple/trunk/modules/webservice/server.cpp $ 00003 version : $LastChangedRevision: 1505 $ $LastChangedBy: jdetaeye $ 00004 date : $LastChangedDate: 2011-08-26 18:55:08 +0200 (Fri, 26 Aug 2011) $ 00005 ***************************************************************************/ 00006 00007 /*************************************************************************** 00008 * * 00009 * Copyright (C) 2007-2011 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 CommandWebservice().commit(); 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::commit() 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 }