mandelbrot.c - OpenLearning
// by Sabrina Rispin
// Activity Section: 5 & 6
// Date: 13/4/15 - 24/4/15
// Description: determines how many steps it takes for a point on the
// complex plane c to escape the funciton z^2 + c upon iteration.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <math.h>
#include "mandelbrot.h"
#include "pixelColor.h"

// server defines
#define SIMPLE_SERVER_VERSION 2.0
#define REQUEST_BUFFER_SIZE 100
#define DEFAULT_PORT 7191
#define NUMBER_OF_PAGES_TO_SERVE 100
// after serving this many pages the server will halt

// defines for escapeSteps, serveBMP and extract
#define TRUE 1
#define FALSE 0
#define MAX_ITER 256
#define SIZE 512    // ie the width of the image (also the height)
#define POWER 2.0    // step = 2^-zoom
#define ESCAPE_DISTANCE 4
#define SIZE_OF_HEADER 54
#define BYTES_PER_PIXEL 10
#define SIZE_OF_BMP (SIZE * SIZE * BYTES_PER_PIXEL)
#define MAX_LEN_INPUT 50
#define OFFSET 2
#define COLOR_MODE 'R'

// bits8 for serveBMP and triordinate for extract
typedef unsigned char  bits8;
typedef struct _triordinate {
   double x;
   double y;
   int z;
} triordinate;
 

static void serveHTML (int socket);
static void serveBMP (int socket, double x, double y, int zoom);
static triordinate extract (char *message);
static int waitForConnection (int serverSocket);
static int makeServerSocket (int portno);


int main (int argc, char* argv[]) {
    // sets up the server
    printf ("************************************\n");
    printf ("Starting simple server %f\n", SIMPLE_SERVER_VERSION);
    printf ("Serving mandelbrots since 2012\n");
    printf ("Access server at http://localhost:%d/\n", DEFAULT_PORT);
    printf ("************************************\n");
 
    int serverSocket = makeServerSocket(DEFAULT_PORT);
    char request[REQUEST_BUFFER_SIZE];
    int numberServed = 0;
    while (numberServed < NUMBER_OF_PAGES_TO_SERVE) {
        printf ("*** So far served %d pages ***\n", numberServed);
 
        // STEP 1. wait for a request to be sent from a web browser, 
        // then open a new connection for this conversation
        int connectionSocket = waitForConnection(serverSocket);
 
        // STEP 2. read the first line of the request
        int bytesRead = recv (connectionSocket, request, sizeof(request) - 1, 0);
        assert (bytesRead >= 0);
        // check that we were able to read some data from the connection
 
        // echo entire request to the console for debugging
        printf (" *** Received http request ***\n %s\n", request);

        // Finds the start and end of the shorter, more useful request
        // from the url. Also checks there is an x, y and z.
        int startReq = 0;
        int endReq = 0;
        int valuesPresent = 0;
        while (request[endReq] != 'H') {
            if (request[endReq] == '/') {
                startReq = endReq;
            }
            if (request[endReq] == 'x' || request[endReq] == 'y' ||
                request[endReq] == 'z') {
                valuesPresent += 1;
            }
            endReq++;
        }

        // Gotta terminate that new string!
        request[endReq] = '\0';
        char *shortRequest = &request[startReq];

        printf("URL Short Request: %s\n", shortRequest);
 
        // STEP 3. send the browser stuff
        printf (" *** Sending http response ***\n");

        // If x y and z serve BMP, else serve html interactive version
        if (valuesPresent == 3) {
            triordinate input = extract (shortRequest);
            serveBMP (connectionSocket, input.x, input.y, input.z);
        } else {
            printf ("HTML TIME\n");
            serveHTML (connectionSocket);
        }
 
        // STEP 4. close the connection after sending the page-
        // keep aust beautiful
        close (connectionSocket);
        ++numberServed;
    }
 
    // close the server connection after we are done-keep aust beautiful
    printf ("** shutting down the server **\n");
    close (serverSocket);
  
    return EXIT_SUCCESS;
}

// mandelbrot functions
int escapeSteps (double x, double y) {
    int escaped = FALSE;
    double zRe = 0.0;
    double zIm = 0.0;

    // need the below in order to simultaneously update
    double newRe = 0.0;
    double newIm = 0.0;

    //printf ("Real c: %lf, Imaginary c: %lf\n", x, y);
    
    // The calcs!
    int iter = 0;
    while ((iter < MAX_ITER) && (escaped != TRUE)) {
        iter++;
        newRe = zRe * zRe - zIm * zIm + x;
        newIm = 2 * zRe * zIm + y;

        zRe = newRe;
        zIm = newIm;

        if (zRe*zRe + zIm*zIm >= ESCAPE_DISTANCE) {
            escaped = TRUE;
        }
    }

    //printf ("%d\n", iter);
    
    return iter;
}

// server functions
static void serveHTML (int socket) {
    char *message;

    // first send the http response header
    message =
        "HTTP/1.0 200 Found\n"
        "Content-Type: text/html\n"
        "\n";
    printf ("about to send=> %s\n", message);
    write (socket, message, strlen (message));

    // serves the html script for the interactive mandelbrot
    message =
        "<!DOCTYPE html>\n"
        "<script src=\"https://almondbread.cse.unsw.edu.au/tiles.js\"></script>"
        "\n";
    write (socket, message, strlen (message));
}


static void serveBMP (int socket, double x, double y, int zoom) {
    char *message;

    // first send the http response header
    message = "HTTP/1.0 200 OK\r\n"
              "Content-Type: image/bmp\r\n"
              "\r\n";
    printf ("about to send=> %s\n", message);
    write (socket, message, strlen (message));

    // serve the BMP header
    bits8 header[SIZE_OF_HEADER] = {
        0x42, 0x4D, 0x36, 0x00, // 
        0x0C, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x36, 0x00,
        0x00, 0x00, 0x28, 0x00,
        0x00, 0x00, 0x00, 0x02,
        0x00, 0x00, 0x00, 0x02,
        0x00, 0x00, 0x01, 0x00,
        0x18, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x0C, 0x00, 0x13, 0x0B,
        0x00, 0x00, 0x13, 0x0B,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };

    write (socket, header, sizeof (header));

    // all the things and counters needed
    double step = pow (POWER, -zoom);
    double xStart = -step*SIZE/2 + step/2 + x;
    double xPos = xStart;
    double yPos = -step*SIZE/2 + step/2 + y;
    int xCount = 0;
    int yCount = 0;
    int arrayPos = 0;
    int iter;

    // the bmp array!
    bits8 bmp[SIZE_OF_BMP];

    while (yCount < SIZE) {
        while (xCount < SIZE) {
            // calcs number of iters to blow up then uses that to color
            iter = escapeSteps (xPos, yPos);
            bits8 blue;
            bits8 red;
            bits8 green;
            if (COLOR_MODE == 'B') {
                blue = stepsToRed (iter);
                red = stepsToGreen (iter);
                green = stepsToBlue (iter);
            } else if (COLOR_MODE == 'G') {
                green = stepsToRed (iter);
                blue = stepsToGreen (iter);
                red = stepsToBlue (iter);
            } else {
                red = stepsToRed (iter);
                green = stepsToGreen (iter);
                blue = stepsToBlue (iter);
            }
            

            // add the pixel
            bmp[arrayPos] = blue;
            arrayPos++;
            bmp[arrayPos] = green;
            arrayPos++;
            bmp[arrayPos] = red;
            arrayPos++;

            // to the next pixel! (Also keeps track of how many pixels)
            xPos += step;  
            xCount++;  
        }

        // at the end of a row reset xPos, add a step to yPos and inc y
        xPos = xStart;
        yPos += step;
        yCount++;
        xCount = 0;
    }

    write (socket, bmp, sizeof (bmp));
}

// extracting x y z function
triordinate extract (char *message) {
    // incase the values after x y and z are empty, set initial vals
    triordinate tri = {0, 0, 7};

    // set start pos at extereme end
    // (not 0, if no update then start will include the whole string!)
    int xStart = strlen (message);
    int yStart = strlen (message);
    int zStart = strlen (message);
    int zEnd = strlen (message) - 1;
    
    // the final x, y and z as strings to go into ato_
    char x[MAX_LEN_INPUT];
    char y[MAX_LEN_INPUT];
    char z[MAX_LEN_INPUT];

    // clears the array by filling it wil escaped 0
    memset (x, '\0', MAX_LEN_INPUT);
    memset (y, '\0', MAX_LEN_INPUT);
    memset (z, '\0', MAX_LEN_INPUT);

    // this loops looks for an _ the looks as the next char
    // if x y or z set correspoding Start value
    // OFFSET = 2 because _x0.4 hence start of num is i (pos of _) + 2
    int i = 0;
    while (i < strlen (message)) {
        if (message[i] == '_') {
            if (message[i+1] == 'x') {
                xStart = i + OFFSET;
            } else if (message[i+1] == 'y') {
                yStart = i + OFFSET;
            } else if (message[i+1] == 'z') {
                zStart = i + OFFSET;
            }
        }

        // _z5.bmp so . is the end of z
        if (message[i] == '.') {
            zEnd = i;
        }
        i++;
    }

    // copies the specific string i.e. -0.4 (from _x-0.4) to x etc.
    // strncpy args: copyToString, copyFromString, length
    // note: yStart - xStart = length of _x-0.4 (-OFFSET for real len)
    strncpy (x, message + xStart, yStart - xStart - OFFSET);
    strncpy (y, message + yStart, zStart - yStart - OFFSET);
    strncpy (z, message + zStart, zEnd - zStart);
    
    //printf ("%s\n", x);
    //printf ("%s\n", y);
    //printf ("%s\n", z);

    // eg if _x_y0.5_z6 there is no x val, strlen (x) == 0, don't update
    if (strlen (x) > 0) {
        tri.x = atof (x);
    }
    if (strlen (y) > 0) {
        tri.y = atof (y);
    }
    if (strlen (z) > 0) {
        tri.z = atol (z);
    }

    return tri;
}

// start the server listening on the specified port number
static int makeServerSocket (int portNumber) {
 
    // create socket
    int serverSocket = socket (AF_INET, SOCK_STREAM, 0);
    assert (serverSocket >= 0);
    // check there was no error in opening the socket
 
    // bind the socket to the listening port  (7191 in this case)
    struct sockaddr_in serverAddress;
    serverAddress.sin_family      = AF_INET;
    serverAddress.sin_addr.s_addr = INADDR_ANY;
    serverAddress.sin_port        = htons (portNumber);
 
    // tell the server to restart immediately after a previous shutdown
    // even if it looks like the socket is still in use
    // otherwise we might have to wait a little while before rerunning the
    // server once it has stopped
    const int optionValue = 1;
    setsockopt (serverSocket, SOL_SOCKET, SO_REUSEADDR, &optionValue, sizeof (int));
 
    int bindSuccess = bind (serverSocket, (struct sockaddr*)&serverAddress, sizeof (serverAddress));
 
    assert (bindSuccess >= 0);
    // if this assert fails wait a short while to let the operating
    // system clear the port before trying again
 
    return serverSocket;
}

// wait for a browser to request a connection,
// returns the socket on which the conversation will take place
static int waitForConnection (int serverSocket) {
 
    // listen for a connection
    const int serverMaxBacklog = 10;
    listen (serverSocket, serverMaxBacklog);
 
    // accept the connection
    struct sockaddr_in clientAddress;
    socklen_t clientLen = sizeof (clientAddress);
    int connectionSocket = accept (serverSocket, (struct sockaddr*)&clientAddress, &clientLen);
    assert (connectionSocket >= 0);
    // check for connection error
 
    return connectionSocket;
}

Download file: mandelbrot.c (11.4 KB)

Comments

Chat