Meltdown – The Computer Lab Prank

I remember that little prank from the days I was a student. You work on an X terminal, and out of the blue, all the display contents gradually disappear’ Pixel after pixel turns black. But don’t worry – you’ll regain control over your display shortly. shortly.
Everyone can access other X terminal display, and mess with it.

How Does It Work?

This program is a simple one using the GDK library, Gnome’s window management package. Including ‘gdk.h’ will also include:

The Program’s Flow

The main function of the program performs the following steps:
1. Initialize GDK.
2. Create a window whose dimensions are the same as those of the root window.
3. Make the window’s background transparent.
4. Make the window a full-screen window.
5. Add an event handler. to handle Expose events.
The event handler will perform the following steps:
1. Create a list of columns and lengths (number of blackened pixels).
2. Create the Graphics Context for the window.
3. Blacken pixels until all pixels are black.
4. Quit the main loop.

Includes And Structures:

#include <stdio.h>
#include <stdlib.h>  
#include <gdk/gdk.h>

GMainLoop *mainloop;
GList *list;

typedef struct col_and_length_t{
  short col;  // Column number
  short len;  // Number of blackened pixels.
} col_and_length;`

The main function:

int main(int argc, char *argv[]){
  gdk_init(NULL, NULL);
  GdkDisplay *disp=gdk_display_get_default();
  GdkScreen *scr = gdk_display_get_default_screen (disp);
  GdkWindow *root = gdk_screen_get_root_window(scr);
  int rootWidth = gdk_window_get_width(root);
  int rootHeight = gdk_window_get_height(root);
  GdkWindowAttr attr;
  attr.width=rootWidth;
  attr.height=rootHeight;
  attr.x=0;
  attr.y=0;
  attr.window_type = GDK_WINDOW_TOPLEVEL;
  attr.wclass=GDK_INPUT_OUTPUT;

  GdkWindow *newWin=gdk_window_new(root,&attr, GDK_WA_X | GDK_WA_Y);
  gdk_event_handler_set (eventFunc, newWin, NULL);
  GdkRGBA color;
  color.alpha=0;

  gdk_window_set_background_rgba(newWin, &color);
  gdk_window_fullscreen(newWin);
  gdk_event_handler_set (eventFunc, newWin, NULL);
  gdk_window_show(newWin);
  mainloop = g_main_new (TRUE);
  g_main_loop_run (mainloop);
  gdk_display_close(disp);

return 0;
}

The event handler

void start_meltdown(GdkWindow *newWin, int height){
  cairo_t *gc=gdk_cairo_create(newWin);
  cairo_set_line_width(gc,2);
  cairo_set_source_rgb (gc, 0, 0, 0);
  int cell_no,size;
  GList *link;
  col_and_length *link_data;
  size=g_list_length(list);

  while(size>0){
    cell_no=random() % size;
    link = g_list_nth(list,cell_no);
    link_data = (col_and_length *)link->data;
    cairo_move_to(gc, link_data->col, link_data->len);
    cairo_rel_line_to(gc, 0, 1);
    cairo_stroke(gc);
    link_data->len++;
    if (link_data->len >= height){
      list=g_list_remove_link(list, link);
      --size;
    }
  }
  g_main_loop_quit(mainloop);
}

void eventFunc(GdkEvent *evt, gpointer data){
  GdkWindow *newWin = (GdkWindow *)data;
  if (gdk_event_get_event_type(evt) == GDK_EXPOSE && gdk_event_get_window (evt) == newWin){
    int width=gdk_window_get_width(newWin);
    int height=gdk_window_get_height(newWin);
    int i;
    for (i=0; i<width;i++){
      col_and_length *cell=(col_and_length *)calloc(sizeof(col_and_length), 1);
      cell->col=i;
      cell->len=0;
      list = g_list_append(list, cell);
    }
    start_meltdown(newWin,height);
  }

}

Compiling

In linux, compiling a program is easy thanks to the pkg-config command.
Run the following from the command line:

gcc meltdown.c `pkg-config --cflags --libs gdk-3.0` -o meltdown

Now, to run the program type:

./meltdown

Written with StackEdit.

Advertisement

Implementing Web Sockets With cURL

WebSocket is an internet protocol that allow full-duplex communication between a client and a TCP/HTTP server. This means that data can be passed in both directions simultaneously. Unlike HTTP, in WebSocket protocol, the client doesn’t have to send a request in order to get responses. Incoming messages are handled by event handlers. HTML5 supports the javascript object WebSocket.  This object has the function ‘send’ that sends a message to the server, and event listener defined by the developer:

onOpen(evt) – Connection Opened.

onMessage(evt) – Message received.

onError(evt) – Error occured.

onClose – Connection Closed.

A little example can be found here.

How to do it with cURL?

cURL does not support the WebSocket protocol. It won’t process a request if the URL string begins with ‘ws://’. You should use the ‘http’ or ‘https’ prefixes instead -for example ‘http://example.com‘, and define request headers and cURL event listeners yourself. In cURL, you’ll define:

  •  A header function using the option ‘CURLOPT_HTTPHEADER’ to check if a connection has been established.
  •  A write function using ‘CURLOPT_WRITEFUNCTION’ to handle in-coming messages.
  •  A socket function using CURLOPT_OPENSOCKETFUNCTION to obtain an IO socket thru which to send messages to the server.

The WebSocket protocol is standardized by RFC 6455,

The following sections will discuss the parts of a C program implementing a Web Socket.

The Main Loop

This part creates a cURL handle by calling curl_easy_init(), defines headers, URL and callback functions using curl_easy_setopt(), and finally call ‘curl_easy_perform().

Following is an example:

#define concat(a,b) a b
  handle = curl_easy_init();
  // Add headers
  header_list_ptr = curl_slist_append(NULL , "HTTP/1.1 101 WebSocket Protocol Handshake");
  header_list_ptr = curl_slist_append(header_list_ptr , "Upgrade: WebSocket");
  header_list_ptr = curl_slist_append(header_list_ptr , "Connection: Upgrade");
  header_list_ptr = curl_slist_append(header_list_ptr , "Sec-WebSocket-Version: 13");
  header_list_ptr = curl_slist_append(header_list_ptr , "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==");
  curl_easy_setopt(handle, CURLOPT_URL, concat("http","://echo.websocket.org"));
  curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list_ptr);
  curl_easy_setopt(handle, CURLOPT_OPENSOCKETFUNCTION, my_opensocketfunc);
  curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, my_func);
  curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, my_writefunc);
  curl_easy_perform(handle);

Obtaining a Socket

The socket is a resource used for sending messages to the server. Messages received from the server will be handled by the write function. Following is a function that returns the desired socket:

curl_socket_t my_opensocketfunc(void *clientp,
curlsocktype purpose,
struct curl_sockaddr *address){

return sock=socket(address->family, address->socktype, address->protocol);
}

The Request Header

The request header is defined in section 4.1 Client Requirements of RFC 6455.

The Response Header

The response header is defined in section 4.2.1. Reading the Client’s Opening Handshake of RFC 6455.

The response header fields should be checked by the header function. The format of a field is:

title: value <CRLF>

When the last field is received, the data contained in the first argument to the header function is a buffer of lenght two bytes,: <CRLF> i.e. byte 0x0d followed by 0x0a.

The structures of responses is defined here.

Sending and Receiving Messages

The format of messages is defined in section 5.2. Base Framing Protocol of RFC 6455.

A simple example is an unmask text message. In such a message the 1st byte will contain the hexadecimal value ‘0x81’. The 1st bit denotes that it is the final fragment, and the last 4 bits denotes a text message. The next byte will contain the length if shorter than 126 bytes. If the length is a 16bit number larger than 125 the byte will hold the value 0x7E, and the following 2 bytes the 16bit length. If the message is longer than 65,535 bytes, the 2nd byte will hold the value 0x7F, and the following 8 bytes will hold the length. The rest of the bytes are the payload data.

To send a message, use the C function ‘write’, as foolows:

write(sock, buff, length);

Incoming messages will be handle by the write function, given as the 3rd parameter to the curl_easy_setopt with the option ‘CURLOPT_WRITEFUNCTION’.

Read more about libcurl here.

Creating Custom Cursors With GDK-Pixbuf-2 And Cairo

Wait! Why use GDK-2 when there ate later stable versions you can download for free? Sometimes you use a tool – such as OpenCV – that integrates with GTK-2, and GDK-2.

Your operating system may allow you to create custom cursor, or mouse pointers, of your own with colors and an alpha channel (opacity). GDK allows you to create a cursor from a pixel buffer (pixbuf), using the function ‘gdk_cursor_new_from_pixbuf‘.  OK, but first let’s make a pixel buffer. In the documentation of GDK 3, I found 2 functions to create a pixbuf: gdk_pixbuf_get_from_window and gdk_pixbuf_get_from_surface. The latter does not exist in GDK-2. However, there is one method, I haven’t found documented` It’s called gdk_pixbuf_new_from_data.  You can get the data from Cairo after you’ve drawn your image using Cairo.

Using Cairo might be a bit confusing because::

  • Cairo uses two data types for color channels: double-precision floating-point numbers and unsigned 8-bit integers.
  • The color of the cursor is not as intended when calling ‘cairo_set_source_rgba’.

The following function in C will demonstrate what I mean:

Here, when the cursor is created its color is yellow, but if you save your created image to a file it will be cyan.

Yellow cursor over the red square.
Yellow cursor over the red square.
The image when saved to a PNG file

The image when saved to a PNG file

void createCursor(){
    double arcEnd=2*M_PI;
    GdkPixbuf *pixbuf;
    int stride=cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, 10); // Will be used later, when we'll create the pixbuf.
    cairo_surface_t *surf=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10); // A canvas of width 10 and height 10.
    cairo_t *cairo_ctx = cairo_create(surf);
    cairo_set_source_rgba(cairo_ctx, 0., 1., 1., 1.); // Double precision values for Red, Green, Blue and Alpha channels between 0 and 1.

    cairo_arc(cairo_ctx,5,5,4,0,arcEnd); // Draw a circle or an arc of a circle whose center is at (5,5) and whose radius is 4
                                         // The arc begins at angle 0 and ends in angle 2Π
    cairo_fill(cairo_ctx); // Fill the circle with cyan, though we've intended to create a yellow one.

    // Create an example image for the blog
    cairo_surface_write_to_png(surf, "/tmp/fortheblog.png");

    guchar *data = cairo_image_surface_get_data(surf); // The data is in BGR, reverse order of RGB !!!

    pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, true, 8, 10, 10, stride, NULL, NULL); // Stride is the difference in bytes between two
                                                                                                      // consecutive rows.
    cursor=gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf, 5, 5);

}

“cursor” in this function is a global variable of type “GdkCursor *”.Now, to add the cursor to a window, use gdk_window_set_cursor.

The “gtk_pixbuf_new_from_data” Function.

This function uses the data returned from the function “cairo_image_surface_get_data”. The data is a pointer to a character. The function receiving the data doesn’t know how many characters are referred to, and how to split it into rows and columns. Following is its prototype:

GdkPixbuf *gdk_pixbuf_new_from_data (const guchar *data,
                     GdkColorspace colorspace,
                     gboolean has_alpha,
                     int bits_per_sample,
                     int width, int height,
                     int rowstride,
                     GdkPixbufDestroyNotify destroy_fn,
                     gpointer destroy_fn_data);

Making C Programmer-Friendly with GNU Libraries

Does anybody remember how to program in C? Well, its syntax is similar to that of languages such as Java, PHP and others, but C uses a data type named pointer, and an array is a pointer, too. When you define an array, the system allocates enough space for it, but when you use the array nobody keeps you from accessing elements out of that array. You will not get a “Subscript out of range” error with the file’s name and line number. What you’ll get instead is a segmentation fault or another variable’s value will change. Use a debugger to find where it happens.
The library GLib has functions that perform operations on data structures like in modern object oriented languages. For example:
Use GArray, and you can enjoy the function ‘g_array_sort’ that sorts using a user-defined comparison function. This structure also allows you to increase the size of your array without calling ‘realloc’ implicitly.
GSList and GList are the data types of singly-linked and doubly-linked respectively, and a ‘foreach’ functions are defined to perform the same operation on each of their elements.
Other data structures are hash-tables, balanced binary trees, N-ary trees, etc.

An interesting utility is the command line option parser, that will check the validity of values passed via the command line and pass the values to function and global variables defined by the user. In addition, this utility will define the ‘–help’ flag, which will print your program’s command line flags and their use.

Of course, this is not everything you can do with GLib, GLib also supports threads and processes, events, etc.

Read more here.

If you want to distribute products you developed using GLib, you might be interested in the license. GLib is distributed under the Lesser GPL license, which means that you can distribute proprietary and open-source software developed with this library.

 

Extending PHP

Extending PHP does not mean just adding classes and functions. It also means adding functionality not previously supported by PHP. This can be done by writing functions in C that can be called from PHP. These functions should be able to receive parameters passed from PHP. The difference between a variable in a C source and a variable in PHP is that in PHP the variable in PHP is loosely typed. That is, in PHP a variable can be used as an integer, but later as a string or a floating point number, so its equivalent in C is zVal. “zval” is a structure containing the variable’s type and a union made up of members of different types sharing the same memory address.

The PHP extension is a dynamically linked library (‘dll’ in Windows, ‘so’ in Linux) containing functions that can be called from PHP.

The process of creating an extension is described in the chapter “PHP at the Core: A Hacker’s Guide to the Zend Engine” in the famous PHP manual.

Building the extension starts with tunning the ‘ext_skel’ script, which creates a directory for your extension including a skeleton of the extension’s C code and a header file.

The next step is to add functions and global variables using macros.

The macro used for defining a  function is PHP_FUNCTION(function_name). Returning a value is done using the macros RETURN_TRUE, RETURN_FALSE, RETVAL_* . These macros are in /path/to/php_include_dir/Zend/zend_API.h

Arguments are passed to local C variables using the function ‘zend_parse_parameters’.

The next step is to edit config.w4(Linux) or config.w32(windows), then run ‘phpize’ and ‘configure’ to create a Makefile.

Finally, run make.

The dynamically loaded library will be created in the ‘modules’ directory. Use ‘make install’ with root permissions to copy your extension to the PHP extension directory.

Unfortunately, the guide is far from being complete, so to look for examples, browse ‘pecl.php.net‘ for source codes.