20 #include "modules/Module.h" 21 #include "modules/system/network-stack/NetworkStack.h" 22 #include "modules/system/vfs/Filesystem.h" 23 #include "modules/system/vfs/VFS.h" 24 #include "pedigree/kernel/Log.h" 25 #include "pedigree/kernel/Version.h" 26 #include "pedigree/kernel/compiler.h" 27 #include "pedigree/kernel/core/SlamAllocator.h" 28 #include "pedigree/kernel/machine/Disk.h" 29 #include "pedigree/kernel/machine/Network.h" 30 #include "pedigree/kernel/process/Process.h" 31 #include "pedigree/kernel/process/Scheduler.h" 32 #include "pedigree/kernel/processor/Processor.h" 38 #define LISTEN_PORT 1234 42 static bool g_Running =
false;
43 static Thread *g_pServerThread =
nullptr;
46 netconnCallback(
struct netconn *conn,
enum netconn_evt evt, u16_t len)
49 if (mutex && (evt == NETCONN_EVT_RCVPLUS || evt == NETCONN_EVT_SENDPLUS ||
50 evt == NETCONN_EVT_ERROR))
57 static int clientThread(
void *p)
62 struct netconn *connection =
reinterpret_cast<struct netconn *
>(p);
63 connection->callback = netconnCallback;
66 bool requestComplete =
false;
71 while (!requestComplete)
73 struct netbuf *buf =
nullptr;
74 if ((err = netconn_recv(connection, &buf)) !=
ERR_OK)
78 WARNING(
"Unexpected disconnection from remote client.");
84 ERROR(
"error in recv: " << lwip_strerr(err));
93 netbuf_data(buf, &data, &len);
97 httpRequest +=
String(reinterpret_cast<char *>(data), len);
99 if (httpRequest.length() >= 4)
106 "HTTP/1.1 400 Bad Request\r\nAllow: GET, " 107 "HEAD\r\nContent-Type: text/plain; " 108 "charset=utf-8\r\n\r\nThe Pedigree built-in status " 109 "server only accepts GET and HEAD requests.";
117 static_cast<const char *>(httpRequest),
"\r\n\r\n"))
120 requestComplete =
true;
124 }
while (netbuf_next(buf) >= 0);
130 netconn_shutdown(connection, 1, 0);
134 if (httpResponse.length())
137 connection, static_cast<const char *>(httpResponse),
138 httpResponse.length(), 0);
139 netconn_shutdown(connection, 1, 1);
142 netconn_close(connection);
143 netconn_delete(connection);
148 bool bHeadRequest = !httpRequest.
startswith(
"GET");
149 bool bNotFound =
false;
152 size_t code = bNotFound ? 404 : 200;
154 statusLine =
"HTTP/1.1 ";
157 statusLine += bNotFound ?
"Not Found" :
"OK";
163 responseContent +=
"Error 404: Page not found.";
167 responseContent +=
"<html><head><title>Pedigree - Live System Status " 168 "Report</title></head><body>";
169 responseContent +=
"<h1>Pedigree Live Status Report</h1>";
170 responseContent +=
"<p>This is a live status report from a running " 171 "Pedigree system.</p>";
172 responseContent +=
"<h3>Current Build</h3><pre>";
176 str +=
"Pedigree - revision ";
177 str += g_pBuildRevision;
178 str +=
"<br />===========================<br />Built at ";
183 str += g_pBuildMachine;
184 str +=
"<br />Build flags: ";
185 str += g_pBuildFlags;
187 responseContent += str;
190 responseContent +=
"</pre>";
192 responseContent +=
"<h3>Network Interfaces</h3>";
194 "<table border='1'><tr><th>Interface</th><th>IP " 195 "Addresses</th><th>Subnet " 196 "Mask</th><th>Gateway</th><th>Driver Name</th><th>MAC " 197 "address</th><th>Statistics</th></tr>";
211 responseContent +=
"<tr><td>";
213 s.append(iface->
name, 2);
214 s.append(iface->
num);
215 responseContent += s;
218 responseContent +=
" <b>(default interface)</b>";
220 responseContent +=
"</td>";
223 responseContent +=
"<td>";
224 const ip4_addr_t *ip4 = netif_ip4_addr(iface);
225 responseContent += ip4addr_ntoa(ip4);
228 const ip6_addr_t *ip6 = netif_ip6_addr(iface, j);
229 if (ip6_addr_isany(ip6))
233 responseContent +=
"<br />";
234 responseContent += ip6addr_ntoa(ip6);
236 responseContent +=
"</td>";
238 const ip4_addr_t *subnet4 = netif_ip4_netmask(iface);
239 const ip4_addr_t *gw4 = netif_ip4_gw(iface);
242 responseContent +=
"<td>";
243 responseContent += ip4addr_ntoa(subnet4);
244 responseContent +=
"</td>";
247 responseContent +=
"<td>";
248 responseContent += ip4addr_ntoa(gw4);
249 responseContent +=
"</td>";
252 responseContent +=
"<td>";
255 responseContent += cardName;
256 responseContent +=
"</td>";
259 responseContent +=
"<td>";
260 responseContent += info.mac.toString();
261 responseContent +=
"</td>";
264 responseContent +=
"<td>";
267 s.append(info.nPackets);
268 s +=
"<br />Dropped: ";
270 s +=
"<br />RX Errors: ";
272 responseContent += s;
273 responseContent +=
"</td>";
275 responseContent +=
"</tr>";
277 responseContent +=
"</table>";
279 responseContent +=
"<h3>VFS</h3>";
281 "<table border='1'><tr><th>VFS Alias</th><th>Disk</th></tr>";
288 for (VFSMountTree::Iterator it = mounts.begin(); it != mounts.end();
292 StringList *pList = it.value();
295 for (StringList::Iterator j = pList->begin(); j != pList->end();
310 diskInfo =
"(no disk)";
312 responseContent +=
"<tr><td>";
313 responseContent += mount;
314 responseContent +=
"</td><td>";
315 responseContent += diskInfo;
316 responseContent +=
"</td></tr>";
320 responseContent +=
"</table>";
323 responseContent +=
"<h3>Memory Usage (KiB)</h3>";
324 responseContent +=
"<table " 325 "border='1'><tr><th>Heap</th><th>Used</th><th>Free</" 329 extern size_t g_AllocedPages;
333 str += SlamAllocator::instance().heapPageCount() * 4;
335 str += (g_AllocedPages * 4096) / 1024;
337 str += (g_FreePages * 4096) / 1024;
339 responseContent += str;
341 responseContent +=
"</table>";
344 responseContent +=
"<h3>Processes</h3>";
347 "border='1'><tr><th>PID</th><th>Description</" 348 "th><th>Virtual Memory (KiB)</th><th>Physical Memory " 349 "(KiB)</th><th>Shared Memory (KiB)</th>";
352 responseContent +=
"<tr>";
356 ssize_t virtK = (pProcess->getVirtualPageCount() * 0x1000) / 1024;
357 ssize_t physK = (pProcess->getPhysicalPageCount() * 0x1000) / 1024;
358 ssize_t shrK = (pProcess->getSharedPageCount() * 0x1000) / 1024;
362 str.append(pProcess->
getId());
363 str.append(
"</td><td>");
365 str.append(
"</td><td>");
366 str.append(virtK, 10);
367 str.append(
"</td><td>");
368 str.append(physK, 10);
369 str.append(
"</td><td>");
370 str.append(shrK, 10);
373 responseContent += str;
374 responseContent +=
"</tr>";
376 responseContent +=
"</table>";
378 responseContent +=
"</body></html>";
382 contentLength.Format(
"\r\nContent-Length: %d", responseContent.length());
384 httpResponse = statusLine;
385 httpResponse += contentLength;
386 httpResponse +=
"\r\nContent-type: text/html; charset=utf-8";
387 httpResponse +=
"\r\nConnection: close";
388 httpResponse +=
"\r\n\r\n";
389 httpResponse += responseContent;
393 g_Netconns.
insert(connection, mutex);
397 connection, static_cast<const char *>(httpResponse),
398 httpResponse.length(), 0);
399 netconn_close(connection);
404 g_Netconns.
remove(connection);
407 netconn_delete(connection);
412 static int mainThread(
void *)
414 struct netconn *server = netconn_new(NETCONN_TCP);
417 ByteSet(&ipaddr, 0,
sizeof(ipaddr));
419 netconn_bind(server, &ipaddr, LISTEN_PORT);
421 netconn_listen(server);
427 struct netconn *connection;
428 if (netconn_accept(server, &connection) ==
ERR_OK)
432 clientThread, connection);
437 netconn_close(server);
438 netconn_delete(server);
445 g_pServerThread =
new Thread(
451 static void destroy()
457 g_pServerThread->
join();
461 MODULE_INFO(
"Status Server", &init, &destroy,
"config",
"lwip");
462 MODULE_OPTIONAL_DEPENDS(
"confignics");
struct netif * netif_default
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
virtual void getName(String &str)
Tree< Filesystem *, List< String * > * > & getMounts()
virtual const StationInfo & getStationInfo()
size_t nBad
Number of packets dropped by the filter.
static ProcessorInformation & information()
Network * getDevice(size_t n)
void insert(const K &key, const E &value)
size_t nDropped
Number of packets passed through the interface.
static Scheduler & instance()
Process * getProcess(size_t n)
virtual void getName(String &str)
static NetworkStack & instance()
virtual void getName(String &str)
LargeStaticString & description()
void remove(const K &key)
#define LWIP_IPV6_NUM_ADDRESSES
bool startswith(const char c) const
Device * getParent() const
E lookup(const K &key) const
struct netif * getInterface(Network *pCard) const