Feedback

Developers

With nearly 10 billion devices connected to the internet and predictions for exponential growth, we’ve reached a point where the space, power, and cost demands of traditional technology are no longer sustainable.
Meg Whitman, President and CEO, HP


Having to Do More

The days of the Desktop PC as the Web client are fading away. Growth comes from many devices – the Internet of things:

  •  2000's ..... Apple ............ Mobile Internet ........ 10 (Units, in Billions)
  •  1990's ..... Google .......... Desktop Internet ......  1
  •  1980's ..... Microsoft ... Desktop PC ...................  0.1

To cope with the geometric growth of these new Internet clients, much more scalable servers are needed. G-WAN is significantly faster and scalable than others, but it is also much easier it is to use.

G-WAN also is safer by-design: adaptive timeouts (rather than fixed-values in config files) let G-WAN automatically block many DoS (Denial of Service) attacks. And unlike Apache or Nginx, G-WAN allocates memory on-demand (rather than upfront), making it possible to both use far less memory and scale as needed (instead of blocking when the limit of concurrent clients is reached).

With nearly all works billed by the hour, ease-of-use and efficiency reduce your costs and therefore boost your margins.


In your favorite  <scripted> language

Use asm C C++ C# D Go Java Javascript Lua Objective-C Perl PHP Python Ruby and Scala scripts with G-WAN. With scripts for both compiled and interpreted languages, G-WAN delivers the productivity that has made less efficient frameworks popular for Web development. (click on language tags to get benchmarks, see them all here)

Why are scripts so useful?

You test your code "live" by just pressing F5 in the Web browser. With Apache, Lighttpd or Nginx C source code modules you have to stop the server, recompile it, and then redeploy it – each time you need to change your code.

G-WAN offers the most of both worlds: efficiency and convenience.


A SERVLET example: 'Hello World'

Servlets are scripts which let G-WAN build dynamic replies for client requests.

By default, C is the "default" language: client requests can ommit the .c file extension (/?hello.c can be invoked as /?hello). You can assign this feature to your favorite language. You can also replace the  ?  (query character) by any character among the URI non-reserved list:  - _ . ! ~ * ' ( )   (see DEFAULT_LANG and QUERY_CHAR).

Deploying one of the servlets below is as simple as copying a source code file in the gwan/.../csp directory:

hello.c

This C script is invoked as follows: http://localhost/?hello.c

1
2
3
4
5
6
7
#include "gwan.h" // G-WAN API

int main(int argc, char *argv[]) 
{
   xbuf_cat(get_reply(argv), "Hello World");
   return HTTP_200_OK; // HTTP status code
}

To change the behavior of hello.c, edit its source code (G-WAN will always serve the latest version saved on disk).

Compare these 7 lines of code to the 120-line Nginx 'Hello World' module (needing a dedicated configuration file).

hello.cpp

This C++ script is invoked as follows: http://localhost/?hello.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "gwan.h" // G-WAN API
#include <string>
using namespace std;
class Hello{
public: 
   void whatsup(xbuf_t *reply, string& str)
   { xbuf_cat(reply, (char*)str.c_str()); }
};
int main(int argc, char *argv[]){
   string h("Hello World"); Hello hello;
   hello.whatsup(get_reply(argv), h);
   return HTTP_200_OK; // HTTP status code
}

hello.cs

This C# script is invoked as follows: http://localhost/?hello.cs

1
2
3
4
5
6
7
8
9
10
using System;

public class hello
{
   public static int Main(string[] args) 
   {
      Gwan.xbufCat(Gwan.getReply(args[0]), "Hello World");
      return 200; // HTTP status (200:'OK')
   }
}

Unsurprisingly, C# having been designed to compete with Java, hello.java and hello.cs are very similar. In our tests , Mono performed slightly better than the JVM, both in performance and memory usage.

hello.java

This Java script is invoked as follows: http://localhost/?hello.java

1
2
3
4
5
6
7
8
9
10
import api.Gwan;

public class hello 
{
   public static int jmain(long env, String[] args) 
   {
      Gwan.xbufCat(Gwan.getReply(env), "Hello World");
      return 200; // HTTP status (200:'OK')
   }
}

Java is "specifically designed to have as few implementation dependencies as possible. Java applications are compiled to bytecode (class file) running on the Java virtual machine (JVM)" ...written in C.

hello.scala

This Scala script is invoked as follows: http://localhost/?hello.scala

1
2
3
4
5
6
7
8
9
10
import api.Gwan;

object hello 
{
   def jmain int(env: Long, args: Array[String]): Int =) 
   {
      Gwan.xbufCat(Gwan.getReply(env), "Hello World");
      return 200; // HTTP status (200:'OK')
   }
}

Scala is based on the JVM (Java Virtual Machine) and aims at making it easier to do parallel-programming tasks.

hello.php

This PHP script is invoked as follows: http://localhost/?hello.php

1
2
3
4
<?php
   echo "Hello World\n";
   exit(200); // HTTP status (200:'OK')
?>

In this example PHP is 'simpler' because no function was defined and no G-WAN API calls were used (but since the original PHP runtime is used, your options are not limited). The same goes for Javascript, Lua, Perl, Python, Ruby, etc.

hello.go

This Go script is invoked as follows: http://localhost/?hello.go

1
2
3
4
5
6
7
8
9
10
package main
 
import "fmt"
import "os"
 
// having the next brace down to the next line gives a syntax error  
func main() {
   fmt.Printf("Hello World")
   os.Exit(200) // return an HTTP code (200:'OK')
}

Like Scala, Google 'Go' is a relatively new language which aims at making it easier to write high-concurrency applications.

hello.py

This Python script is invoked as follows: http://localhost/?hello.py

1
2
3
4
5
import os
import sys
 
print 'Hello World'
sys.exit(200) // return an HTTP code (200:'OK')

Python is an high-level language which "supports multiple programming paradigms, including object-oriented, imperative and functional programming or procedural styles".

hello.pl

This Perl script is invoked as follows: http://localhost/?hello.pl

1
2
3
print "Hello World";

exit 200; # return an HTTP code (200:'OK')

Perl is an high-level language which "gained widespread popularity in the late 1990s as a CGI scripting language, in part due to its parsing abilities".

hello.rb

This Ruby script is invoked as follows: http://localhost/?hello.rb

1
2
3
puts 'Hello World';

exit(200); # return an HTTP code (200:'OK')

Ruby is an high-level language which "dynamic, reflective, and object-oriented design combines a syntax inspired by Perl with Smalltalk-like features".

hello.lua

This Lua script is invoked as follows: http://localhost/?hello.lua

1
2
3
io.stdout:write("Hello World")

os.exit(200) -- return an HTTP code (200:'OK')

Lua is an high-level language which "lightweight multi-paradigm design targets 'extensible semantics' as a primary goal".

hello.js

This Javascript script is invoked as follows: http://localhost/?hello.js

1
2
3
console.log("Hello World")

process.exit(200); // return an HTTP code (200:'OK')

Javascript is an high-level language which was "originally implemented as part of web browsers. More recently, it has been used in server-side programming".

hello.m

This Objective-C script is invoked as follows: http://localhost/?hello.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import "gwan.h" // G-WAN API
#import <objc/Object.h>

@interface Hello : Object { xbuf_t*replyBuffer; }
- (Hello*)initWithBuffer:(xbuf_t*)reply;
- (void)whatsup;
@end

@implementation Hello 
- (Hello*)initWithBuffer:(xbuf_t*)reply
{ 
   replyBuffer = reply; 
   return self; 
}
- (void)whatsup
{
   xbuf_cat(replyBuffer, "Hello World");
}
@end

int main(int argc, char *argv[])
{
   Hello *hello = [[Hello alloc] initWithBuffer:get_reply(argv)];  
   [hello whatsup];
   [hello free];
   return HTTP_200_OK; // HTTP status code
}

G-WAN also supports Objective-C++ (with the .mm file extension) and GNUstep, both of which are very popular on Apple computers and mobile devices.


Note that to return an empty reply you should use return HTTP_204_NO_CONTENT; (or exit(204) for CGI scripts) because return 0; (RC_CLOSE = 0; in gwan.h), or no return code at all, tells G-WAN to gracefully close the connection.

In contrast, return 1; (an [1-99] invalid HTTP code) will prevent G-WAN from generating HTTP headers (which may be handy to return a non-HTTP reply like a raw JSON payload, see RC_NOHEADERS = 1 in gwan.h).

Whatever the language, deploying or updating G-WAN scripts does not require configuration (nor any delay: the latest version is executed on-the-fly). And, as a bonus, Java and C# scripts are served as fast as C scripts by G-WAN, making them fly higher than ever: see these commented benchmark charts comparing G-WAN+Java to Tomcat.


Syntax Errors & Crash Reports

Before running a script, G-WAN reports compilation errors and indicates the offending line(s) in the source code:

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Error: hellox.c
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /gwan/0.0.0.0_8080/#0.0.0.0/csp/hellox.c:
 In function 'main':
 /csp/hellox.c:7:14: error: 'repl' undeclared (first use in this function)
 /csp/hellox.c:3:12: warning: unused variable 'reply'

  3 |    xbuf_t *reply = get_reply(argv);
  4 |    char *name = 0;
  5 |    get_arg("name=", &name, argc, argv);
  6 | 
  7 !    xbuf_xcat(repl, "Hello %H", (name && *name) ? name : "you");
  8 |    
  9 |    return HTTP_200_OK;
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Identifying the cause of execution errors must be as straightforward as possible. To fix bugs, you just want to know where in your source code the problem happens. Revert to multi-page core dumps only if you have to.

G-WAN execution error reports indicate the offending source code file and line number in the call chain:

 Script: crash_libc.c
 Client: 127.0.0.1
 Query : ?crash_libc

 Signal        : 11:Address not mapped to object
 Signal src    : 1:SEGV_MAPERR
 errno         : 0
 Thread        : 0
 Code   Pointer: 0000f5200b33 (module:/lib/libc.so.6, function:strcpy, line:0)
 Access Address: 00000badc0de

 Registers     : EAX=00000badc0de CS=00000033 EIP=0000f5200b33 EFLGS=000000010202
                 EBX=000000000001 SS=ec2d8ed4 ESP=0000f5ded828 EBP=0000f5dee020
                 ECX=000033323130 DS=ec2d8ed4 ESI=0000ec2d8f86 FS=00000033
                 EDX=000003b03c00 ES=ec2d8ed4 EDI=00000badc0de CS=00000033

 Module        :Function        :Line # PgrmCntr(EIP)  RetAddress  FramePtr(EBP)
      libc.so.6:          strcpy:     - 0000f5200b33 0000ec2d8f00   0000f5dee020
        servlet:            main:    37 0000ec2d8f00 00000042e10c   0000f5dee020        

Servlet crashes do not stop G-WAN. Errors are logged if log files are enabled (useful in daemon mode), and reported on stderr if G-WAN runs in a terminal. Fix the bug and just press [F5] in the Web browser to run the script again.

This makes life easier, allows to write and test code much faster, and makes bug hunting easier than system core dumps.


LIBRARIES

Use databases like IBM DB2 MySQL ORACLE PostgreSQL SQLite, support new output formats like PDF PNG SVG with libcairo, and talk to other SSL FTP IMAP POP3 SMTP LDAP servers with libcurl.

Instead of having to write a new module for each library (like for Apache or Nginx), just use the #pragma link directive in your G-WAN servlets or handlersthere is absolutely no interface code to write:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma link "curl"    // link this servlet with the cURL library (no configuration)
#include <curl/curl.h> // include cURL definitions
#include "gwan.h"      // G-WAN API

int main(int argc, char *argv[]) 
{
   xbuf_t *reply = get_reply(argv), xbuf;
   xbuf_init(&xbuf);
   
   if(http_get("curl.haxx.se/libcurl/c/", &xbuf) != CURLE_OK)
      xbuf_cat(reply, "Server or resource not available");
   else
      xbuf_ncat(reply, xbuf.ptr, xbuf.len);
      
   xbuf_free(&xbuf);   
   return HTTP_200_OK; // HTTP status code
}

The cURL library alone supports DICT FILE FTP(S) GOPHER HTTP(S) IMAP(S) LDAP POP3(S) RTMP RTSP SCP SFTP SMTP(S) TELNET and TFTP!

If you are short of inspiration then look at /usr/lib. There are thousands of pre-installed libraries ready-to-use from G-WAN, and even more libraries are available from Linux repositories.


HANDLERS

Unlike G-WAN servlets (used to build dynamic contents), G-WAN handlers can also modify the behavior of the server.

This is useful to implement (IP address or content-type) filters, to rewrite client requests, to define how HTTP errors will be processed, or to add custom features – including new network protocols.

Content-Type handlers are called by G-WAN when a client queried a specific file type (such as HTML or GIF):

FLV.C – Pseudo-Streaming

The Flash Player client can ask a Web server from which position a movie should be downloaded. This extra feature is implemented as pre-compiled C modules by other servers like Apache, Lighttpd or Nginx.

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(int argc, char *argv[]) 
{
   char *query = get_env(argv, QUERY_STRING, 0); // query: "start=200000"
   if(!query || memcmp(query, "start=", sizeof("start=") - 1)) // FLV query?
      return 200; // HTTP status (200:'OK')
   
   http_t *head = get_env(argv, HTTP_HEADERS, 0); // set HTTP bytes range
   head->h_range_from = atol(query + sizeof("start=") - 1); // checked by G-WAN

   #define FLV_HEAD "FLV\x1\x1\0\0\0\x9\0\0\0\x9" // insert the FLV Header
   http_header(HEAD_ADD | HEAD_AFTER, FLV_HEAD, sizeof(FLV_HEAD) - 1, argv);
   return HTTP_206_PARTIAL_CONTENTS; // HTTP status code
}

This FLV content-type handler is stored as /gwan/.../handlers/flv.c (filenames match the MIME type).

Compare these 13 lines to the modules of Apache (137 lines), Lighttpd (352 lines) and Nginx (257 lines).

The G-WAN C script above is much shorter to write, far faster to execute and incredibly easier to maintain.

General-purpose connection handlers (called main.c) let you alter the behavior of the server at each possible step of a connection (ACCEPT, READ, PARSING, BUILDING, HTTP_ERROR, REPLYING, etc.).

URL rewriting

Here a connection handler is used to rewrite /blog requests into /?blog requests to involve dynamic contents:

1
2
3
4
5
7
6
8
9
10
11
12
13
int main(int argc, char *argv[])
{
   const long state = (long)argv[0];
   if(state == HDL_AFTER_READ)
   {
      xbuf_t *read_xbuf = (xbuf_t*)get_env(argv, READ_XBUF);
      xbuf_replfrto(read_xbuf, read_xbuf->ptr, read_xbuf->ptr + 16, "/blog", "/?blog");

      // Note: you may have to look for the ending double-CRLF to check
      //       if there are other pipelined requests to rewrite
   }
   return 255; // execute next connection step
}

These examples illustrate how C scripts seriously fit the task of rapid (and efficient) Web development – especially when used from a Web framework designed to make things as simple as they should be.

Protocol handlers (in upppercase: SMTP.c, POP3.c, LDAP.c, etc.) let you use G-WAN scripts to implement the network protocols your infrastructure may need. Whether you want to implement a custom reverse-proxy or a database server, you can build on the top of G-WAN's proven architecture instead of starting from scratch.

PONG.c

The 'PONG' protocol handler sends a "PONG" HTTP reply to all requests. A more complete and commented version is provided as an example here and in the G-WAN download archive. Look at how simple it is to add a network protocol to G-WAN:

1
2
3
4
5
7
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#pragma debug  // get symbols in crash reports (line numbers, functions, arguments)
enum PRT_states // our user-defined protocol states
{
   PRT_FREE,     // unused connection slot
   PRT_ACCEPTED, // a new connection was accepted by the G-WAN listener
   PRT_READING,  // data can be fetched from the input socket buffer
   PRT_SENDING,  // data can be added to the output socket buffer
   PRT_CLOSING   // the connection was closed (client close or error)
};

int main(int argc, char *argv[])
{
   conn_t *C = (void*)argv[0]; // update the connection state with I/O events
   if(C->state == PRT_FREE && C->accepted) C->state = PRT_ACCEPTED; else
   if(C->closing) C->state = PRT_CLOSING;

   switch(C->state) // process connection states
   {
      case PRT_ACCEPTED:
         C->state = PRT_READING; // now wait for incoming data
         break;

      case PRT_READING:
      {
         if(!C->can_recv) 
            break; // the input socket buffer is empty, wait for data to come
         
         char buf[1024] = {0};
         int bytes = 0;
         for(;;)
         {
            const int ret = recv(C->fd, &buf, sizeof(buf), 0);
            if(ret <= 0) // closed, no more bytes, errors...
               break;
            bytes += ret;
         }
         
         C->state = PRT_SENDING;
         //break; // here we don't break to send immediately if possible
      }

      case PRT_SENDING:
      {
         if(!C->can_send) 
            break; // the output socket buffer is full, wait for free room

         static const char reply[] = "HTTP/1.1 200 OK\r\n"
                                     "Content-Length: 5\r\n"
                                     "Content-Type: text/html\r\n"
                                     "Connection: close\r\n\r\nPONG\n";
         int bytes = send(C->fd, reply, sizeof(reply) - 1, 0);
         return 0; // close this connection
      }

      case PRT_CLOSING: // G-WAN is gracefully closing the connection
         break;
   }
   return 1; // 1:continue, 0:gracefully close connection
}

G-WAN Protocol handlers make it easier, faster and more efficient to write and test prototypes as well as to deliver enterprise-ready solutions. You can either implement and market new G-WAN features or fill a gap in your own infrastructure.


To go further, read the servlet and handler examples in the download archive and check the G-WAN API reference.


Streaming Made Easy

Streaming can be implemented in handlers as see above, but this can also be done from servlets, and quite simply.

Here is a streaming example made without G-WAN's Comet capabilities: each second, a new PING step appears in the HTML page, without any AJAX or Javascript – and G-WAN is not blocking during those ~10 seconds:

 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
 64 bytes from 127.0.0.1: icmp_req=1 ttl=64 time=0.028 ms   (step #1)
 64 bytes from 127.0.0.1: icmp_req=2 ttl=64 time=0.032 ms   (step #2)
 64 bytes from 127.0.0.1: icmp_req=3 ttl=64 time=0.026 ms   (...)
 64 bytes from 127.0.0.1: icmp_req=4 ttl=64 time=0.015 ms
 64 bytes from 127.0.0.1: icmp_req=5 ttl=64 time=0.023 ms
 64 bytes from 127.0.0.1: icmp_req=6 ttl=64 time=0.022 ms
 64 bytes from 127.0.0.1: icmp_req=7 ttl=64 time=0.027 ms
 64 bytes from 127.0.0.1: icmp_req=8 ttl=64 time=0.030 ms
 64 bytes from 127.0.0.1: icmp_req=9 ttl=64 time=0.035 ms
 64 bytes from 127.0.0.1: icmp_req=10 ttl=64 time=0.028 ms

 --- 127.0.0.1 ping statistics ---
 10 packets transmitted, 10 received, 0% packet loss, time 8996ms
 rtt min/avg/max/mdev = 0.015/0.026/0.035/0.007 ms

How much code is necessary to do that? Let have a look: (this "stream3.c" script is heavily commented in the download archive)

1
2
3
4
5
7
6
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
int main(int argc, char *argv[])
{
   char readbuf[1024] = {0};
   xbuf_t *reply = get_reply(argv);
   data_t **data = (void*)get_env(argv, US_REQUEST_DATA);
   if(!*data) // we did not setup our per-request structure yet
   {
      if(!gc_init(argv, 4070)) // we can now call gc_alloc() to consume 4070 bytes
         return HTTP_503_SERVICE_UNAVAILABLE; // HTTP status code
      
      *data = gc_malloc(argv, sizeof(data_t)); // allocate our context
      if(!*data) return 503; // not possible here, but better safe than sorry
      
      (*data)->f = run_cmd("ping -c " NBR_CHUNKS " 127.0.0.1"); // replacing popen()
      if((*data)->f == 0) // error?
      {
         int ret = strerror_r(errno, readbuf, sizeof(readbuf));
         xbuf_cat(reply, ret ? "unknown error" : readbuf);
         return HTTP_200_OK; // HTTP status code
      }
      
      wake_up(argv, (*data)->f, WK_FD); // when fd buffer has data
      char head[] = "HTTP/1.1 200 OK\r\n"
                    "Connection: close\r\n"
                    "Content-type: text/html; charset=utf-8\r\n"
                    "Transfer-Encoding: chunked\r\n\r\n"
                    "5\r\n<pre>\r\n";
      xbuf_ncat(reply, head, sizeof(head) - 1);
   }

   const int len = read((*data)->f, readbuf, sizeof(readbuf)); // fetch reply chunk
   if(len <= 0) // command reply is completed
   {
      close((*data)->f);
      char end[] = "6\r\n</pre>\r\n0\r\n\r\n"; // close chunked stream
      xbuf_ncat(reply, end, sizeof(end) - 1);
      wake_up(argv, 0, WK_FD); // 0:no more wake-up please
      return RC_NOHEADERS; // RC_NOHEADERS: do not generate HTTP headers
   }

   xbuf_xcat(reply, "%x\r\n%s\r\n", len, readbuf); // close this chunk
   return RC_NOHEADERS + RC_STREAMING; // keep streaming...
}

G-WAN lets you focus on your application rather than on cornersome implementation details.

Kids will like the Dying Art of Code Optimization again

After the CPU frequency halt ( "The free lunch is over") and with increasingly tight budgets and raising energy costs, efficiency will soon directly make the difference between success and failure – whether your projects are small, or not.

The trend of stacking abstraction layers has created unsustainable bottlenecks in the Cloud and in the corporate infrastructure. Today, necessity mades "bare-to-the-metal" fashionable again. And not many tools are helping legacy investments to survive the parallelism programming challenge with G-WAN's ease of use and efficiency.