ROME2 Lab7
Embed:
(wiki syntax)
Show/hide line numbers
HTTPServer.cpp
00001 /* 00002 * HTTPServer.cpp 00003 * Copyright (c) 2020, ZHAW 00004 * All rights reserved. 00005 */ 00006 00007 #include <algorithm> 00008 #include "HTTPScript.h" 00009 #include "HTTPServer.h" 00010 00011 using namespace std; 00012 00013 inline string int2String(int i) { 00014 00015 char buffer[32]; 00016 sprintf(buffer, "%d", i); 00017 00018 return string(buffer); 00019 } 00020 00021 const unsigned int HTTPServer::INPUT_BUFFER_SIZE = 1024; // size of receive buffer, given in [bytes] 00022 const int HTTPServer::SOCKET_TIMEOUT = 1000; // timeout of socket, given in [ms] 00023 00024 /** 00025 * Create and initialize an http server object. 00026 * @param ethernet a reference to the embedded TCP/IP stack to use. 00027 */ 00028 HTTPServer::HTTPServer(EthernetInterface& ethernet) : ethernet(ethernet), thread(osPriorityNormal, STACK_SIZE) { 00029 00030 // start thread 00031 00032 thread.start(callback(this, &HTTPServer::run)); 00033 } 00034 00035 /** 00036 * Delete the http server object. 00037 */ 00038 HTTPServer::~HTTPServer() {} 00039 00040 /** 00041 * Registers the given script with the http server. 00042 * This allows to call a method of this script object 00043 * through virtual cgi-bin requests from a remote system. 00044 */ 00045 void HTTPServer::add(string name, HTTPScript* httpScript) { 00046 00047 httpScriptNames.push_back(name); 00048 httpScripts.push_back(httpScript); 00049 } 00050 00051 /** 00052 * Decodes a given URL string into a standard text string. 00053 */ 00054 string HTTPServer::urlDecoder(string url) { 00055 00056 size_t pos = 0; 00057 while ((pos = url.find("+")) != string::npos) url = url.substr(0, pos)+" "+url.substr(pos+1); 00058 while ((pos = url.find("%08")) != string::npos) url = url.substr(0, pos)+"\b"+url.substr(pos+3); 00059 while ((pos = url.find("%09")) != string::npos) url = url.substr(0, pos)+"\t"+url.substr(pos+3); 00060 while ((pos = url.find("%0A")) != string::npos) url = url.substr(0, pos)+"\n"+url.substr(pos+3); 00061 while ((pos = url.find("%0D")) != string::npos) url = url.substr(0, pos)+"\r"+url.substr(pos+3); 00062 while ((pos = url.find("%20")) != string::npos) url = url.substr(0, pos)+" "+url.substr(pos+3); 00063 while ((pos = url.find("%22")) != string::npos) url = url.substr(0, pos)+"\""+url.substr(pos+3); 00064 while ((pos = url.find("%23")) != string::npos) url = url.substr(0, pos)+"#"+url.substr(pos+3); 00065 while ((pos = url.find("%24")) != string::npos) url = url.substr(0, pos)+"$"+url.substr(pos+3); 00066 while ((pos = url.find("%25")) != string::npos) url = url.substr(0, pos)+"%"+url.substr(pos+3); 00067 while ((pos = url.find("%26")) != string::npos) url = url.substr(0, pos)+"&"+url.substr(pos+3); 00068 while ((pos = url.find("%2B")) != string::npos) url = url.substr(0, pos)+"+"+url.substr(pos+3); 00069 while ((pos = url.find("%2C")) != string::npos) url = url.substr(0, pos)+","+url.substr(pos+3); 00070 while ((pos = url.find("%2F")) != string::npos) url = url.substr(0, pos)+"/"+url.substr(pos+3); 00071 while ((pos = url.find("%3A")) != string::npos) url = url.substr(0, pos)+":"+url.substr(pos+3); 00072 while ((pos = url.find("%3B")) != string::npos) url = url.substr(0, pos)+";"+url.substr(pos+3); 00073 while ((pos = url.find("%3C")) != string::npos) url = url.substr(0, pos)+"<"+url.substr(pos+3); 00074 while ((pos = url.find("%3D")) != string::npos) url = url.substr(0, pos)+"="+url.substr(pos+3); 00075 while ((pos = url.find("%3E")) != string::npos) url = url.substr(0, pos)+">"+url.substr(pos+3); 00076 while ((pos = url.find("%3F")) != string::npos) url = url.substr(0, pos)+"?"+url.substr(pos+3); 00077 while ((pos = url.find("%40")) != string::npos) url = url.substr(0, pos)+"@"+url.substr(pos+3); 00078 00079 return url; 00080 } 00081 00082 /** 00083 * This <code>run()</code> method binds the TCP/IP server to a given port number 00084 * and enters an infinite loop that waits for http requests and then processes 00085 * these requests and returns a response. 00086 */ 00087 void HTTPServer::run() { 00088 00089 // bind the server to a given port number 00090 00091 server.open(ðernet); 00092 server.bind(PORT_NUMBER); 00093 server.listen(); 00094 00095 // enter infinite loop 00096 00097 while (true) { 00098 00099 TCPSocket* client = server.accept(); 00100 if (client != NULL) { 00101 00102 client->set_blocking(true); 00103 client->set_timeout(SOCKET_TIMEOUT); // set timeout of socket 00104 00105 // read input 00106 00107 char buffer[INPUT_BUFFER_SIZE]; 00108 int size = client->recv(buffer, sizeof(buffer)); 00109 00110 if (size > 0) { 00111 00112 string input(buffer, size); 00113 string header; 00114 string output; 00115 00116 // parse input 00117 00118 if ((input.find("GET") == 0) || (input.find("HEAD") == 0)) { 00119 00120 if (input.find("cgi-bin") != string::npos) { 00121 00122 // process script request with arguments 00123 00124 string script = input.substr(input.find("cgi-bin/")+8, input.find(" ", input.find("cgi-bin/")+8)-input.find("cgi-bin/")-8); 00125 string name; 00126 vector<string> names; 00127 vector<string> values; 00128 00129 if (script.find("?") != string::npos) { 00130 00131 name = script.substr(0, script.find("?")); 00132 script = script.substr(script.find("?")+1); 00133 00134 vector<string> arguments; 00135 while (script.find("&") != string::npos) { 00136 arguments.push_back(script.substr(0, script.find("&"))); 00137 script = script.substr(script.find("&")+1); 00138 } 00139 arguments.push_back(script); 00140 00141 for (int i = 0; i < arguments.size(); i++) { 00142 00143 if (arguments[i].find("=") != string::npos) { 00144 00145 names.push_back(arguments[i].substr(0, arguments[i].find("="))); 00146 values.push_back(urlDecoder(arguments[i].substr(arguments[i].find("=")+1))); 00147 00148 } else { 00149 00150 names.push_back(arguments[i]); 00151 values.push_back(""); 00152 } 00153 } 00154 00155 } else { 00156 00157 name = script; 00158 } 00159 00160 // look for corresponding script 00161 00162 for (int i = 0; i < min(httpScriptNames.size(), httpScripts.size()); i++) { 00163 00164 if (httpScriptNames[i].compare(name) == 0) { 00165 00166 output = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"; 00167 output += "<!DOCTYPE html>\r\n"; 00168 output += "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\r\n"; 00169 output += "<body>\r\n"; 00170 output += httpScripts[i]->call(names, values); 00171 output += "</body>\r\n"; 00172 output += "</html>\r\n"; 00173 00174 header = "HTTP/1.1 200 OK\r\n"; 00175 header += "Content-Length: "+int2String(output.size())+"\r\n"; 00176 header += "Content-Type: text/xml\r\n"; 00177 header += "Expires: 0\r\n"; 00178 header += "\r\n"; 00179 00180 output = header+output; 00181 } 00182 } 00183 00184 // requested script was not found on this server 00185 00186 if ((output).size() == 0) { 00187 00188 output = "<!DOCTYPE html>\r\n"; 00189 output += "<html lang=\"en\">\r\n"; 00190 output += "<head>\r\n"; 00191 output += " <title>404 Not Found</title>\r\n"; 00192 output += " <style type=\"text/css\">\r\n"; 00193 output += " h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n"; 00194 output += " p {font-family:Helvetica,Arial,sans-serif; font-size: 14; color:#444444;}\r\n"; 00195 output += " </style>\r\n"; 00196 output += "</head>\r\n"; 00197 output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n"; 00198 output += " <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"0\" cellpadding=\"20\">\r\n"; 00199 output += " <tr>\r\n"; 00200 output += " <th width=\"100%\" height=\"30\" bgcolor=\"#0064A6\"><h2>400 Bad Request</h2></th>\r\n"; 00201 output += " </tr>\r\n"; 00202 output += " <tr>\r\n"; 00203 output += " <td valign=\"top\">\r\n"; 00204 output += " <p>The requested script could not be found on this server!</p>\r\n"; 00205 output += " </td>\r\n"; 00206 output += " </tr>\r\n"; 00207 output += " </table>\r\n"; 00208 output += "</body>\r\n"; 00209 output += "</html>\r\n"; 00210 00211 header = "HTTP/1.1 404 Not Found\r\n"; 00212 header += "Content-Length: "+int2String(output.size())+"\r\n"; 00213 header += "Content-Type: text/html\r\n"; 00214 header += "\r\n"; 00215 00216 output = header+output; 00217 } 00218 00219 // write output 00220 00221 void* address = (void*)(output).c_str(); 00222 int offset = 0; 00223 while (offset < (output).size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), (output).size()-offset); 00224 00225 } else { 00226 00227 // transmit static file 00228 00229 output = "<!DOCTYPE html>\r\n"; 00230 output += "<html lang=\"en\">\r\n"; 00231 output += "<head>\r\n"; 00232 output += " <meta charset=\"utf-8\"/>\r\n"; 00233 output += " <title>Sensor Fusion</title>\r\n"; 00234 output += " <style type=\"text/css\">\r\n"; 00235 output += " html {background-color: #223344;}\r\n"; 00236 output += " h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n"; 00237 output += " p, td {font-family:Helvetica,Arial,sans-serif; font-size: 16; color:#EEEEEE;}\r\n"; 00238 output += " </style>\r\n"; 00239 output += "</head>\r\n"; 00240 output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n"; 00241 output += " <script type=\"text/javascript\">\r\n"; 00242 output += " var tiltAngleA = [];\r\n"; 00243 output += " var tiltAngleG = [];\r\n"; 00244 output += " var tiltAngleK = [];\r\n"; 00245 output += " var tiltAngleC = [];\r\n"; 00246 output += " var xmlhttp = null;\r\n"; 00247 output += " var task = window.setInterval(\"update()\", 50);\r\n"; 00248 output += " function update() {\r\n"; 00249 output += " if (window.XMLHttpRequest) {\r\n"; 00250 output += " xmlhttp = new XMLHttpRequest();\r\n"; 00251 output += " } else if (window.ActiveXObject) {\r\n"; 00252 output += " try {\r\n"; 00253 output += " xmlhttp = new ActiveXObject(\"Msxml2.XMLHTTP\");\r\n"; 00254 output += " } catch (exception) {\r\n"; 00255 output += " try {\r\n"; 00256 output += " xmlhttp = new ActiveXObject(\"Microsoft.XMLHTTP\");\r\n"; 00257 output += " } catch (exception) {}\r\n"; 00258 output += " }\r\n"; 00259 output += " }\r\n"; 00260 output += " xmlhttp.onreadystatechange = refresh;\r\n"; 00261 output += " xmlhttp.open(\"GET\", \"/cgi-bin/tiltAngle\");\r\n"; 00262 output += " xmlhttp.send(null);\r\n"; 00263 output += " }\r\n"; 00264 output += " function refresh() {\r\n"; 00265 output += " if (xmlhttp.readyState == 4) {\r\n"; 00266 output += " var xml = xmlhttp.responseXML;\r\n"; 00267 output += " var floatValues = xml.getElementsByTagName(\"float\");\r\n"; 00268 output += " tiltAngleA.push(floatValues[0].childNodes[0].nodeValue/Math.PI*180.0); if (tiltAngleA.length > 400) tiltAngleA.shift();\r\n"; 00269 output += " tiltAngleG.push(floatValues[1].childNodes[0].nodeValue/Math.PI*180.0); if (tiltAngleG.length > 400) tiltAngleG.shift();\r\n"; 00270 output += " tiltAngleK.push(floatValues[2].childNodes[0].nodeValue/Math.PI*180.0); if (tiltAngleK.length > 400) tiltAngleK.shift();\r\n"; 00271 output += " tiltAngleC.push(floatValues[3].childNodes[0].nodeValue/Math.PI*180.0); if (tiltAngleC.length > 400) tiltAngleC.shift();\r\n"; 00272 output += " drawPlot(\"tiltAngle\", tiltAngleA, tiltAngleG, tiltAngleK, tiltAngleC, \"°\");\r\n"; 00273 output += " }\r\n"; 00274 output += " }\r\n"; 00275 output += " function drawPlot(id, value0, value1, value2, value3, valueUnit) {\r\n"; 00276 output += " var canvas = document.getElementById(id);\r\n"; 00277 output += " var width = window.innerWidth-50;\r\n"; 00278 output += " var height = window.innerHeight-50;\r\n"; 00279 output += " canvas.width = 2*width;\r\n"; 00280 output += " canvas.height = 2*height;\r\n"; 00281 output += " canvas.style.width = width+\"px\";\r\n"; 00282 output += " canvas.style.height = height+\"px\";\r\n"; 00283 output += " var ctx = canvas.getContext(\"2d\");\r\n"; 00284 output += " ctx.scale(2,2);\r\n"; 00285 output += " ctx.fillStyle = \"#334455\";\r\n"; 00286 output += " ctx.fillRect(0.5, 0.5, width-1, height-1);\r\n"; 00287 output += " var valueMin = value0[0];\r\n"; 00288 output += " var valueMax = value0[0];\r\n"; 00289 output += " for (i = 0; i < Math.min(Math.min(value0.length, value1.length), value2.length); i++) {\r\n"; 00290 output += " valueMin = Math.min(valueMin, Math.min(value0[i], Math.min(value1[i], Math.min(value2[i], value3[i]))));\r\n"; 00291 output += " valueMax = Math.max(valueMax, Math.max(value0[i], Math.max(value1[i], Math.max(value2[i], value3[i]))));\r\n"; 00292 output += " }\r\n"; 00293 output += " if (valueMax-valueMin < 2.0/Math.pow(10.0, 3)) {\r\n"; 00294 output += " var valueMean = (valueMin+valueMax)/2.0;\r\n"; 00295 output += " valueMin = valueMean-1.0/Math.pow(10.0, 3);\r\n"; 00296 output += " valueMax = valueMean+1.0/Math.pow(10.0, 3);\r\n"; 00297 output += " }\r\n"; 00298 output += " var valueStep = (valueMax-valueMin)/(height/100); if (valueStep < 1.0/Math.pow(10.0, 3)) valueStep = 1.0/Math.pow(10.0, 3);\r\n"; 00299 output += " var valueGain = Math.pow(10.0, Math.floor(Math.log(valueStep)/Math.log(10.0)));\r\n"; 00300 output += " valueStep = valueStep/valueGain;\r\n"; 00301 output += " if (valueStep > 5.0) valueStep = 5.0*valueGain; else if (valueStep > 2.0) valueStep = 2.0*valueGain; else valueStep = valueGain;\r\n"; 00302 output += " valueMin = Math.floor(valueMin/valueStep-0.25)*valueStep;\r\n"; 00303 output += " valueMax = Math.ceil(valueMax/valueStep+0.25)*valueStep;\r\n"; 00304 output += " ctx.strokeStyle = \"#EEEEEE\";\r\n"; 00305 output += " ctx.lineWidth = 1;\r\n"; 00306 output += " ctx.beginPath();\r\n"; 00307 output += " for (valueCurrent = valueMin+valueStep; valueCurrent < valueMax-valueStep/2.0; valueCurrent += valueStep) {\r\n"; 00308 output += " ctx.moveTo(0, (valueMax-valueCurrent)/(valueMax-valueMin)*height+0.5);\r\n"; 00309 output += " ctx.lineTo(width, (valueMax-valueCurrent)/(valueMax-valueMin)*height+0.5);\r\n"; 00310 output += " }\r\n"; 00311 output += " ctx.stroke();\r\n"; 00312 00313 output += " ctx.font = \"normal 16px sans-serif\";\r\n"; 00314 output += " ctx.textBaseline = \"bottom\";\r\n"; 00315 output += " ctx.fillStyle = \"white\";\r\n"; 00316 output += " for (valueCurrent = valueMin+valueStep; valueCurrent < valueMax-valueStep/2.0; valueCurrent += valueStep) {\r\n"; 00317 output += " ctx.fillText(valueCurrent.toFixed(2), 10.0, (valueMax-valueCurrent)/(valueMax-valueMin)*height-5.0);\r\n"; 00318 output += " }\r\n"; 00319 output += " ctx.fillStyle = \"#FF0000\";\r\n"; 00320 output += " ctx.fillText(\"Tilt Angle from Accelerometer: \"+(value0[value0.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, 40);\r\n"; 00321 output += " ctx.fillStyle = \"#FFFF00\";\r\n"; 00322 output += " ctx.fillText(\"Tilt Angle from Gyro: \"+(value1[value1.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, 65);\r\n"; 00323 output += " ctx.fillStyle = \"#00FF00\";\r\n"; 00324 output += " ctx.fillText(\"Tilt Angle from Kalman-Filter: \"+(value2[value2.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, 90);\r\n"; 00325 output += " ctx.fillStyle = \"#00AA00\";\r\n"; 00326 output += " ctx.fillText(\"Tilt Angle from Complementary Filter: \"+(value3[value3.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, 115);\r\n"; 00327 00328 output += " ctx.strokeStyle = \"#FF0000\";\r\n"; 00329 output += " ctx.lineWidth = 2;\r\n"; 00330 output += " ctx.beginPath();\r\n"; 00331 output += " ctx.moveTo(0, (valueMax-value0[0])/(valueMax-valueMin)*height+0.5);\r\n"; 00332 output += " for (i = 1; i < value0.length; i++) {\r\n"; 00333 output += " ctx.lineTo(i/(value0.length-1)*width, (valueMax-value0[i])/(valueMax-valueMin)*height+0.5);\r\n"; 00334 output += " }\r\n"; 00335 output += " ctx.stroke();\r\n"; 00336 00337 output += " ctx.strokeStyle = \"#FFFF00\";\r\n"; 00338 output += " ctx.lineWidth = 2;\r\n"; 00339 output += " ctx.beginPath();\r\n"; 00340 output += " ctx.moveTo(0, (valueMax-value1[0])/(valueMax-valueMin)*height+0.5);\r\n"; 00341 output += " for (i = 1; i < value1.length; i++) {\r\n"; 00342 output += " ctx.lineTo(i/(value1.length-1)*width, (valueMax-value1[i])/(valueMax-valueMin)*height+0.5);\r\n"; 00343 output += " }\r\n"; 00344 output += " ctx.stroke();\r\n"; 00345 00346 output += " ctx.strokeStyle = \"#00FF00\";\r\n"; 00347 output += " ctx.lineWidth = 2;\r\n"; 00348 output += " ctx.beginPath();\r\n"; 00349 output += " ctx.moveTo(0, (valueMax-value2[0])/(valueMax-valueMin)*height+0.5);\r\n"; 00350 output += " for (i = 1; i < value2.length; i++) {\r\n"; 00351 output += " ctx.lineTo(i/(value2.length-1)*width, (valueMax-value2[i])/(valueMax-valueMin)*height+0.5);\r\n"; 00352 output += " }\r\n"; 00353 output += " ctx.stroke();\r\n"; 00354 00355 output += " ctx.strokeStyle = \"#00AA00\";\r\n"; 00356 output += " ctx.lineWidth = 2;\r\n"; 00357 output += " ctx.beginPath();\r\n"; 00358 output += " ctx.moveTo(0, (valueMax-value3[0])/(valueMax-valueMin)*height+0.5);\r\n"; 00359 output += " for (i = 1; i < value3.length; i++) {\r\n"; 00360 output += " ctx.lineTo(i/(value3.length-1)*width, (valueMax-value3[i])/(valueMax-valueMin)*height+0.5);\r\n"; 00361 output += " }\r\n"; 00362 output += " ctx.stroke();\r\n"; 00363 00364 output += " ctx.strokeStyle = \"white\";\r\n"; 00365 output += " ctx.lineWidth = 1;\r\n"; 00366 output += " ctx.strokeRect(0.5, 0.5, width-1, height-1);\r\n"; 00367 output += " }\r\n"; 00368 output += " </script>"; 00369 output += " <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"20\" cellpadding=\"0\">\r\n"; 00370 output += " <tr>\r\n"; 00371 output += " <th><canvas id=\"tiltAngle\"></canvas></th>\r\n"; 00372 output += " </tr>\r\n"; 00373 output += " </table>\r\n"; 00374 output += "</body>\r\n"; 00375 output += "</html>\r\n"; 00376 00377 header = "HTTP/1.1 404 Not Found\r\n"; 00378 header += "Content-Length: "+int2String(output.size())+"\r\n"; 00379 header += "Content-Type: text/html\r\n"; 00380 header += "\r\n"; 00381 00382 output = header+output; 00383 00384 // write output 00385 00386 void* address = (void*)output.c_str(); 00387 int offset = 0; 00388 while (offset < output.size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), output.size()-offset); 00389 } 00390 00391 } else { 00392 00393 // the http method is not known 00394 00395 output = "<!DOCTYPE html>\r\n"; 00396 output += "<html lang=\"en\">\r\n"; 00397 output += "<head>\r\n"; 00398 output += " <title>400 Bad Request</title>\r\n"; 00399 output += " <style type=\"text/css\">\r\n"; 00400 output += " h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n"; 00401 output += " p {font-family:Helvetica,Arial,sans-serif; font-size: 14; color:#444444;}\r\n"; 00402 output += " </style>\r\n"; 00403 output += "</head>\r\n"; 00404 output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n"; 00405 output += " <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"0\" cellpadding=\"20\">\r\n"; 00406 output += " <tr>\r\n"; 00407 output += " <th width=\"100%\" height=\"30\" bgcolor=\"#0064A6\"><h2>400 Bad Request</h2></th>\r\n"; 00408 output += " </tr>\r\n"; 00409 output += " <tr>\r\n"; 00410 output += " <td valign=\"top\">\r\n"; 00411 output += " <p>The requested method is not supported by this server!</p>\r\n"; 00412 output += " </td>\r\n"; 00413 output += " </tr>\r\n"; 00414 output += " </table>\r\n"; 00415 output += "</body>\r\n"; 00416 output += "</html>\r\n"; 00417 00418 header = "HTTP/1.1 400 Bad Request\r\n"; 00419 header += "Content-Length: "+int2String(output.size())+"\r\n"; 00420 header += "Content-Type: text/html\r\n"; 00421 header += "\r\n"; 00422 00423 output = header+output; 00424 00425 // write output 00426 00427 void* address = (void*)output.c_str(); 00428 int offset = 0; 00429 while (offset < output.size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), output.size()-offset); 00430 } 00431 } 00432 00433 client->close(); 00434 00435 } // client != NULL 00436 00437 } // infinite while loop 00438 } 00439
Generated on Fri Jul 29 2022 01:28:48 by
1.7.2