Monday, June 2, 2014

Create your own web server in C/C++



Here I'll outline steps to create basic web server on Linux in C/C++ using sockets.

Let's begin with list of ingredients:

1. We need to open a socket for listening purpose by calling following function:

   int socket(int domain, int type, int protocol);

2.  Next we need to bind the homeless socket just created to some address (port) using call to this function:

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

3. The trap is set. Now wait for the game.

    int listen(int sockfd, int backlog);

4. Accept a connection as it comes and receive the data:

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);

    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
   int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);

    ssize_t recv(int sockfd, void *buf, size_t len, int flags);

5. Send your response

    ssize_t send(int sockfd, const void *buf, size_t len, int flags);

6. Shutdown the connection and close the client socket

    int shutdown(int sockfd, int how);

    int close(int fd);

Here's the client code:

 /* This page contains the client program. The following one contains the
 * server program. Once the server has been compiled and started, clients
 * anywhere on the Internet can send commands (file names) to the server.
 * The server responds by opening and returning the entire file requested.
 */

#include <sys types.h="">
#include <sys socket.h="">
#include <netinet in.h="">
#include <netdb .h="">
#include <string .h="">

#define SERVER_PORT 12345  /* arbitrary, but client and server must agree */
#define BUF_SIZE 4096   /* block transfer size */

int main(int argc, char **argv)
{
  int c, s, bytes;
  char buf[BUF_SIZE];   /* buffer for incoming file */
  struct sockaddr_in channel;  /* holds IP address */

  if (argc != 2) fatal("Usage: client file-name");

  s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (s < 0) fatal("socket");
  memset(&channel, 0, sizeof(channel));
  channel.sin_family= AF_INET;
  
  inet_pton ( AF_INET, "localhost", &channel.sin_addr );
  channel.sin_port= htons(SERVER_PORT);

  c = connect(s, (struct sockaddr *) &channel, sizeof(channel));
  if (c < 0) fatal("connect failed");
  /* Connection is now established. Send file name including 0 byte at end. */
  write(s, argv[1], strlen(argv[1])+1);

  /* Go get the file and write it to standard output. */
  while (1) {
        bytes = read(s, buf, BUF_SIZE); /* read from socket */
        if (bytes <= 0) exit(0); /* check for end of file */
        write(1, buf, bytes);  /* write to standard output */
  }
}

fatal(char *string)
{
  printf("%s\n", string);
  exit(1);
}

And the server code:

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define SERVER_PORT 12345  /* arbitrary, but client and server must agree */
#define BUF_SIZE 4096   /* block transfer size */
#define QUEUE_SIZE 10

int main(int argc, char *argv[])
{ 
  int s, b, l, fd, sa, bytes, on = 1;
  char buf[BUF_SIZE];   /* buffer for outgoing file */
  struct sockaddr_in channel;  /* hold's IP address */

  /* Build address structure to bind to socket. */
  memset(&channel, 0, sizeof(channel)); /* zero channel */
  channel.sin_family = AF_INET;
  channel.sin_addr.s_addr = htonl(INADDR_ANY);
  channel.sin_port = htons(SERVER_PORT);

  /* Passive open. Wait for connection. */
  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* create socket */
  if (s < 0) fatal("socket failed");
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));

  b = bind(s, (struct sockaddr *) &channel, sizeof(channel));
  if (b < 0) fatal("bind failed");

  l = listen(s, QUEUE_SIZE);  /* specify queue size */
  if (l < 0) fatal("listen failed");

  /* Socket is now set up and bound. Wait for connection and process it. */
  while (1) {
        sa = accept(s, 0, 0);  /* block for connection request */
        if (sa < 0) fatal("accept failed");

        read(sa, buf, BUF_SIZE); /* read file name from socket */

        /* Get and return the file. */
        fd = open(buf, O_RDONLY); /* open the file to be sent back */
        if (fd < 0) fatal("open failed");

        while (1) {
                bytes = read(fd, buf, BUF_SIZE); /* read from file */
                if (bytes <= 0) break;   /* check for end of file */
                write(sa, buf, bytes);   /* write bytes to socket */
        }
        close(fd);     /* close file */
        close(sa);     /* close connection */
  }
}

fatal(char *string)
{
  printf("%s", string);
  exit(1);
}
 
Based on Tanenbaum, "Computer Networks" 

Clang vs GCC

Yes, Clang is definitely more focused and colorful at error reporting than GCC.

It might compile faster than GCC (though I didn't observe that).

Running my own graphics program showed Clang generated executable to be slightly slower than GCC generated executable. Frame-rate was 0.22% less and CPU utilization was 4.37% less for Clang generated executable.

Here's the raw data for those who are interested:

Clang generated executable:
  44.151 FPS
  Consumed 1 second of CPU time every 9.544 seconds

GCC generated executable:
  44.247 FPS
  Consumed 1 second of CPU time every 9.980 seconds

Sunday, April 6, 2014

Scientific vs Non-scientific claims

There's no easy way to distinguish between scientific and not-scientific claims but it will be interesting to know what faction of academic research passes the following tests:

  1. Let the claim statement be S.
  2. Let entire set of reasoning used to prove that S is true be R.
  3. Let the entire set of data used to obtain inferences R be D.

Check the system
  1. Make sure that D is free from instrument or observer error.
  2. Make sure that R is obtained by performing mathematically and physically sound analysis of D.
  3. Make sure that S can be concluded from R.

Check the complementary system (alternate contending models)
  1. Make sure that there are no hidden D' in the system that will lead to (or falsify) conclusions R because D might itself be a side-effect of D' and hence not being the cause of R.
  2. Make sure there are no hidden R' which are in fact responsible for possible truthfulness (or falsification) of S and R merely being side-effect of R'. (Here D' and R' together form alternate contending models proving or disproving S)

Test the system
Make sure that the effect of D used to support R and subsequently statement S has been correctly identified by removing the ingredients from D one or two or many at a time and trying to predict the outcome S' in absence of those sets of ingredients. If predictions match the actual outcome S' it is very likely that the effects of ingredients in D have been correctly understood.


The overall result will be a probability value indicating how correct claim S is. This value is subject to improve or diminish or fluctuate when more observations, data and analysis tools are made available over time. For example, if the number of strongly contending models increases, truthfulness of S should diminish.


Comments:

  1. Where do all the data come from?
  2. Every belief is false unless there's no better explanation available.

Sunday, January 19, 2014

Having trouble with laptop brightness settings on Ubuntu or Fedora?

Simple, yet effective method. Has been tested on many older HP and Lenovo systems.

1. Open the file /etc/default/grub and look for GRUB_CMDLINE_LINUX="quiet splash".

2. Change it to:
GRUB_CMDLINE_LINUX="quiet splash acpi_backlight=vendor"

3. Save the file and reboot.

Your First JavaScript Animation

You can create a quick animation using JavaScript in about 10 lines of code. All you need are Gedit and Firefox, both being available by default on your system.

Create an html file, say test.html, with the following contents:

<!-- test.html -->

<!--
This animation uses two boxes, one big and another small. The small box moves inside the big box. These two boxes are created using following two "div" objects:
-->

<div style="width:1000;height:550;border-style:solid;border-width:2" />
<!--This div element is 1000 pixels wide and 550 pixels heigh. It has got a solid border of 2 pixel thickness.-->

<div id="square" style="width:100;height:100;border-style:solid;border-width:2;border-color:purple;background-color:yellowgreen;">
</div>
<!--This div object is a 100 pixel wide square. Its name/id has been set to the word "square" for easy identification. It also has a solid border of 2 pixel thickness. This border is purple and the box is shaded with yellow-green color. -->

<script>
//This small script describes the interaction between the two boxes declared above.

//First we create a javascript variable called "box" which actually refers to the second div object (whose id was manually set to the word "square").

var box = document.getElementById("square");

//We create a variable "dist" which stores the distance moved by the box along X and Y axis during each frame of animation. The higher this distance, the faster will the small box move.
var dist = 2;

//posX and posY are meant to store the x and y coordinates of the top left corner of the small box. 
//dirX indicates if the small box is moving in positive or negative X direction. If the value of dirX is +dist, posX is increasing and if the value of dirX is -dist then posX is decreasing. Initially both dirX and dirY are +dist.
var posX=0, posY=0, dirX=dist, dirY=dist;

//Function move() will move the small box and then set a timer to call itself again.
function move()
{
  
  //Update the position variables by distance stored in dirX and dirY
    posX += dirX;
    posY += dirY;
  
  //If posX is 0, it means small box is touching LEFT edge of the big box.
  //If posX is 1000-100 then the small box is touching the RIGHT edge of the big box.
    if( posX < 0 ) dirX = dist; else if( posX > 1000-100 ) dirX = -dist; 
  
  //If posY is 0, small box is touching TOP edge of the big box.
  //If posY is 550-100 then small box is touching BOTTOM edge of the big box.
    if( posY < 0 ) dirY = dist; else if( posY > 550-100 ) dirY = -dist; 
  
  //Assign the position stored in posX and posY as the actual position of the small box.
    box.style.marginLeft = posX;
    box.style.marginTop = posY;
   
  //To continue animation execute the function move() again after 10 milliseconds.
  setTimeout( move, 10 );  //milliseconds
}

//So far we have only defined what the function move() is. Now we should call move() so that it starts running. Once move() starts running it will never stop because move() is calling itself recursively. The animation will continue forever until the browser window is closed.
move();

</script>

Open the file test.html in Firefox.

That's it.

Tuesday, December 24, 2013

What to do during and after Ubuntu 13.10 installation

Here's the complete workflow I use to set up Ubuntu 13.10:

A. GENERAL CONSIDERATIONS DURING FRESH INSTALLATION
  1. Allocate a 50GB partition and install the system there.

  2. After installation immediately set the root password and create a new user with limited access.
 
  3. Log on as the new limited user and utilize all free disk space to create multiple encrypted partitions.

  4. Restore all backed up data to the encrypted partitions.

B. FIGHTING UBUNTU'S IDIOSYNCRASIES:
  1. Visit fixubuntu.com and copy and execute commands from there. This will disable automatic online search and make several privacy enhancements.

  2. Remap HUD Key which is "left alt" by default to something else
    System settings -> Keyboard > Shortcuts > Launchers -> HUD key -> ctrl-alt-h  

  3. Open Software & Updates and disable multiverse to keep updates light.
 
  4. Modify "security and privacy" settings to your requirements.

  5. Disable paid software as described in another post.
 
  6. Uninstall useless software to keep updates light.
    apt-get autoremove gnome-contacts ubuntuone-control-panel-qt gnome-mines unity-lens-photos aisleriot gnome-mahjongg gnome-sudoku empathy remmina thunderbird vino unity-scope-gdrive rhythmbox totem gnome-control-center-signon gnome-user-share landscape-client-ui-install gnome-orca onboard deja-dup  

C. INSTALL UPDATES AND ESSENTIAL SOFTWARE
  apt-get update && apt-get upgrade
 

  apt-get install geany g++ vlc gimp ghex alarm-clock-applet compizconfig-settings-manager

D. TWEAK GNOME/UNITY 
  1. Get rid of folders cluttering the home folder. To store your personal files use encrypted partitions created earlier.
    rmdir ~/Public/ ~/Documents/ ~/Music/ ~/Pictures/ ~/Videos/ ~/Downloads/ ~/Templates/
    rm ~/examples.desktop
 

  2. If the system text is too small, scale it by an appropriate factor:
    gsettings set org.gnome.desktop.interface text-scaling-factor '1.35' 

  3. If F4 requires Fn+F4, remap close window key to Super-Q: 
    gsettings set org.gnome.desktop.wm.keybindings close "['<Super>Q']" 

  4. Highly recommended: Set bottom left screen corner to initiate window picker.
    $ ccsm
      Advanced Search >>  Scale >> Binding >> Initiate Window Picker >> Bottomleft


  5. Disable gedit as root (we'll be using geany instead):
    cd /usr/bin
    mv gedit gedit.backup
    Right click a .txt file and in its property dialog set default application as geany.
 
E. APPLICATION SPECIFIC MODIFICATIONS   
  1. Make geany more usable:
    Open geany and in preferences dialog:
      unselect interface->show sidebar
      unselect interface->show statusbar
      select editor->features->line wrapping
    In the main menu:
      unselect view->show message window
      unselect view->show toolbar

  2. Add adblock plus plug-in to firefox.