Procster  0.1
Procster-ViewProcessesovertheweb
procserver.c File Reference

Process server (main()) More...

#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <microhttpd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <jansson.h>
#include <ctype.h>
#include "proclister.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
Include dependency graph for procserver.c:

Data Structures

struct  connection_info_struct
 MHD connection/request Helper data structure for maintaining the "state" of request data reading / parsing (as data is read in chunks) for HTTP methods that have a HTTP Body (POST, PUT). More...
 

Macros

#define MHD_PLATFORM_H
 
#define POSTBUFFERSIZE   256
 
#define con_info_need_mem(con_info, cnt)   (con_info->used + cnt + 1)
 
#define parse_no_state(c)   (!c)
 Macros for detecting parsing state (from MHD multiple calls to response handler). More...
 
#define parse_starting(c)   ((!*con_cls) && (!c->is_parsing) && (c->is_parsing = 1) && (*con_cls = c))
 
#define parse_running(c)   ((*con_cls) && (c->is_parsing == 1))
 
#define parse_ending(c)   ((*con_cls) && (!*upload_data_size) && (c->is_parsing) && (c->is_parsing = 2))
 

Typedefs

typedef struct connection_info_struct CONNINFO
 

Enumerations

enum  ConnectionType { GET = 0, POST = 1 }
 
enum  ParsingState { INITED =0, PARSING, COMPLETE }
 

Functions

char * proc_list_json (int flags)
 Create a process list directly from readproc() listing as JSON. More...
 
static int send_page (struct MHD_Connection *connection, const char *page, int status_code)
 Generic string content sending. More...
 
void con_info_destroy (CONNINFO *con_info)
 Destroy POST Request info freeing all allocated memory. More...
 
CONNINFOcon_info_create (struct MHD_Connection *connection)
 Allocate CONNINFO for POST Parsing. More...
 
int post_body_parse (struct MHD_Connection *connection, const char *upload_data, size_t *upload_data_size, void **con_cls)
 Parse POST Body incrementally. More...
 
int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls)
 MHD POST Handler example. More...
 
int answer_to_connection1 (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls)
 Legacy: Generic POST Handler with POST Body parsing. More...
 
struct MHD_Response * trystatic (const char *url)
 Try to resolve url to a static file and return response for it. More...
 
int basic_creds_ok (struct MHD_Connection *connection)
 Check HTTP Basic credentials. More...
 
int pid_extract (const char *url)
 Extract pid number from (relative) Web URL. More...
 
int answer_to_connection0 (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls)
 MHD Response handler for creating OS Process listing. More...
 
void req_term_cb (void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
 Post request Callback launched by MHD after completing request. More...
 
int savepid (json_t *json)
 
void daemon_prep ()
 
void daemon_launch (int port, json_t *json)
 
int main (int argc, char *argv[])
 Main for (Micro HTTP Daemon) process app. More...
 

Variables

char docroot [256] = {0}
 

Detailed Description

Process server (main())

Compiling

gcc -o procserver procserver.c -lmicrohttpd

Info on MHD development

Info on Ulfius

TODO

  • Consider where "tree" model can be created - at server or client ?
    • In either 1 or 2 pass algorithm (or between) ? Does sorting help (if processes overflowed 64K (general case), not)
    • Need hashtables in C for server side tree structuring ?
  • Use json_t *json_deep_copy(const json_t *value) or just parse template string for error message

    Mem leakges

Poll each 3000 ms Case 1

  • Linear mode, one proc_t node in stack
  • JSON un-freed (No json_decref()), Use json_object_set, NOT json_object_set_new
  • Response memmode MHD_RESPMEM_PERSISTENT
  • 205MB/2:30 82MB / hr Case 2
  • Set serialized JSON string "page" memmode = MHD_RESPMEM_MUST_FREE;
  • 45MB / 35min 52MB/43 min 55MB/45min 73MB/ 1hr => (derived) 183MB/2.5hr 73.3MB/hr Case 3
  • Additionally Use
    • json_object_set_new() (OLD: json_object_set) on obj member additions
      • Better yet: json_object_set_new_nocheck() - No key UTF-8 check
    • json_array_append_new() (OLD: json_array_append()) on array add
    • json_decref(obj)
  • Does Practically not leak memory.

Macro Definition Documentation

◆ con_info_need_mem

#define con_info_need_mem (   con_info,
  cnt 
)    (con_info->used + cnt + 1)

Referenced by con_info_create(), and post_body_parse().

◆ MHD_PLATFORM_H

#define MHD_PLATFORM_H

◆ parse_ending

#define parse_ending (   c)    ((*con_cls) && (!*upload_data_size) && (c->is_parsing) && (c->is_parsing = 2))

Referenced by answer_to_connection().

◆ parse_no_state

#define parse_no_state (   c)    (!c)

Macros for detecting parsing state (from MHD multiple calls to response handler).

Macros have to be called in the order they appear here (See also example for post_body_parse()). This is because they also change the state of the parsing. These macros eliminate the calls to parser.

Todo:
: Name parsing_* instead of parse_* (?)

Referenced by answer_to_connection().

◆ parse_running

#define parse_running (   c)    ((*con_cls) && (c->is_parsing == 1))

Referenced by answer_to_connection().

◆ parse_starting

#define parse_starting (   c)    ((!*con_cls) && (!c->is_parsing) && (c->is_parsing = 1) && (*con_cls = c))

Referenced by answer_to_connection().

◆ POSTBUFFERSIZE

#define POSTBUFFERSIZE   256

Typedef Documentation

◆ CONNINFO

Enumeration Type Documentation

◆ ConnectionType

Enumerator
GET 
POST 

◆ ParsingState

Enumerator
INITED 
PARSING 
COMPLETE 

Function Documentation

◆ answer_to_connection()

int answer_to_connection ( void *  cls,
struct MHD_Connection *  connection,
const char *  url,
const char *  method,
const char *  version,
const char *  upload_data,
size_t *  upload_data_size,
void **  con_cls 
)

◆ answer_to_connection0()

int answer_to_connection0 ( void *  cls,
struct MHD_Connection *  connection,
const char *  url,
const char *  method,
const char *  version,
const char *  upload_data,
size_t *  upload_data_size,
void **  con_cls 
)

MHD Response handler for creating OS Process listing.

Example of simple GET handling of HTTP Request.

References MHD_add_response_header(), MHD_create_response_from_buffer(), MHD_destroy_response(), pid_extract(), proc_kill(), proc_list_json2(), proc_tree(), ptree_free(), ptree_json(), and trystatic().

Referenced by daemon_launch().

◆ answer_to_connection1()

int answer_to_connection1 ( void *  cls,
struct MHD_Connection *  connection,
const char *  url,
const char *  method,
const char *  version,
const char *  upload_data,
size_t *  upload_data_size,
void **  con_cls 
)

Legacy: Generic POST Handler with POST Body parsing.

See: MHD_post_process and MHD_create_post_processor MHD_ContentReaderFreeCallback MHD_RequestCompletedCallback set by MHD_OPTION_NOTIFY_COMPLETED (2 pointer params)

References con_info_destroy(), connection_info_struct::is_parsing, MHD_add_response_header(), MHD_create_response_from_buffer(), MHD_destroy_response(), MHD_YES, post_body_parse(), connection_info_struct::postdata, and send_page().

◆ basic_creds_ok()

int basic_creds_ok ( struct MHD_Connection *  connection)

Check HTTP Basic credentials.

◆ con_info_create()

CONNINFO* con_info_create ( struct MHD_Connection *  connection)

Allocate CONNINFO for POST Parsing.

CONNINFO is used to keep track of body retrieval / buffering state across multiple calls to MHD answer_to_connection() request handler callback.

Parameters
connection- MHD connection / request struct
Returns
App specific HTTP Request object (BODY data reading state mgr)

References con_info_destroy(), con_info_need_mem, connection_info_struct::contlen, connection_info_struct::conttype, connection_info_struct::debug, connection_info_struct::postdata, and connection_info_struct::size.

Referenced by answer_to_connection().

◆ con_info_destroy()

void con_info_destroy ( CONNINFO con_info)

Destroy POST Request info freeing all allocated memory.

It is recommended that this is called in the MHD main handler or req_term_cb() (which ? Both passed to MHD_start_daemon() as 5th and 8th params respectively).

References connection_info_struct::conttype, and connection_info_struct::postdata.

Referenced by answer_to_connection(), answer_to_connection1(), con_info_create(), and req_term_cb().

◆ daemon_launch()

void daemon_launch ( int  port,
json_t json 
)

References answer_to_connection0(), and savepid().

Referenced by main().

◆ daemon_prep()

void daemon_prep ( )

Referenced by main().

◆ main()

int main ( int  argc,
char *  argv[] 
)

Main for (Micro HTTP Daemon) process app.

5th param to MHD_start_daemon() defines the main connection handler (that should do respective dispatching if app handles many different actions).

References daemon_launch(), daemon_prep(), and docroot.

◆ pid_extract()

int pid_extract ( const char *  url)

Extract pid number from (relative) Web URL.

Parameters
url- procserver kill process URL
Returns
pid number or 0 on failure to extract pid properly

Referenced by answer_to_connection0().

◆ post_body_parse()

int post_body_parse ( struct MHD_Connection *  connection,
const char *  upload_data,
size_t *  upload_data_size,
void **  con_cls 
)

Parse POST Body incrementally.

This gets called multiple times as a result of MHD answer_to_connection() being called multiple times with request types that have HTTP Body present.

The state of request processing and body parsing is reflected in con_info.state in follwing ways:

  • INITED (0) - con_info has been allocated and returned via param list con_cls
  • PARSING (1) - the fragments being passed by calls to answer_to_connection() are being parsed.
  • COMPLETE (2) - when body parsing has been completed, all POST content stored.
    Parameters
    connection- MHD Connection
    upload_data- Incoming POST data fragment (to add to collected POST data)
    upload_data_size- Size of new fragment
    con_cls- MHD Request specific user-data, Here: CONNINFO *
    Returns
    MHD_NO for fatal errors that should terminate whole HTTP request, MHD_YES for valid state and progression of parsing. A typical usage within answer_to_connection() might look like this: ...

References con_info_need_mem, connection_info_struct::debug, connection_info_struct::is_parsing, MHD_YES, connection_info_struct::postdata, connection_info_struct::size, and connection_info_struct::used.

Referenced by answer_to_connection(), and answer_to_connection1().

◆ proc_list_json()

char* proc_list_json ( int  flags)

Create a process list directly from readproc() listing as JSON.

For flags see FLAGS in man openproc.

Parameters
flagsThe openproc() flags that define the extent of parsing process info from /proc/$PID (There are ~ 20 flags available).
Returns
Dynamically allocated process listing JSON string or NULL in case of errors (error messages get written to stderr).
Todo:

Make process attibutes more configurable. Possibly corralate fields to generate to flags passed as input (need lookup tables for those).

Possibly wrap response with additional JSON object to be able to convey status and error messages.

References IS_KTHREAD, and PROC_FLAGS_DEFAULT.

◆ req_term_cb()

void req_term_cb ( void *  cls,
struct MHD_Connection *  connection,
void **  con_cls,
enum MHD_RequestTerminationCode  toe 
)

Post request Callback launched by MHD after completing request.

References con_info_destroy().

◆ savepid()

int savepid ( json_t json)

Referenced by daemon_launch().

◆ send_page()

static int send_page ( struct MHD_Connection *  connection,
const char *  page,
int  status_code 
)
static

Generic string content sending.

Parameters
connectionMHD_Connection / single request (See MHD Docs)
page- Page as (null terminated) text
status_code- HTTP numeirc status code (e.g. 200, 400. ...) to send with response
Returns
Return the kind of values that MHD request handler returns (MHD_NO, ...).
Todo:
Add len for binary data (allow -1 to measure string)

References MHD_create_response_from_buffer(), and MHD_destroy_response().

Referenced by answer_to_connection(), and answer_to_connection1().

◆ trystatic()

struct MHD_Response* trystatic ( const char *  url)

Try to resolve url to a static file and return response for it.

Parameters
url- Request URL to test for static content
Returns
MHD_Response (pointer) for static file or NULL
Todo:
: Check suffix and try to map to appropriate mime-type

References docroot, MHD_create_response_from_fd(), and connection_info_struct::size.

Referenced by answer_to_connection0().

Variable Documentation

◆ docroot

char docroot[256] = {0}

Referenced by main(), server_new(), and trystatic().