// 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)