#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "mandelbrot.h"
#include "common.h"
static int verbose;
int file_write (const unsigned char *data, size_t length, void *arg) {
size_t ret = fwrite(data, length, 1, (FILE *) arg);
return (ret == 1) ? RENDER_CB_OK : RENDER_CB_ERR;
}
void render_local (int img_w, int img_h, FILE *output) {
struct render_ctx ctx;
render_ctx_set(&ctx, &file_write, NULL, output);
double duration;
if (mandelbrot_render_full_timed(
&ctx,
img_w, img_h,
&duration
) != MANDELBROT_OK)
err_exit("mandelbrot_render_region failed");
if (verbose)
fprintf(stdout, "rendered %dx%d mandelbrot in %f seconds\n", img_w, img_h, duration);
}
void render_remote (int img_w, int img_h, FILE *output, FILE *remote) {
struct render_cmd cmd;
if (render_cmd_set_full(&cmd, img_w, img_h) != MANDELBROT_OK) {
err_exit("mandelbrot_render_remote failed");
}
int ret = fwrite((void *) &cmd, sizeof(cmd), 1, remote);
if (ret != 1)
perr_exit("fwrite(remote)");
if (verbose)
printf("sent render command of %zu bytes\n", sizeof(cmd));
// shuffle data around
while (!feof(remote)) {
char buf[1024];
int bytes = fread(buf, 1, sizeof(buf), remote);
if (bytes)
if (fwrite(buf, bytes, 1, output) != 1)
perr_exit("fwrite(output)");
}
if (verbose)
printf("got PNG data\n");
if (ferror(remote))
perr_exit("fread(remote)");
}
FILE *open_remote (char *remote) {
char *addr_str, *port_str = NULL;
addr_str = strsep(&remote, ":");
if (remote)
port_str = remote;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port_str ? atoi(port_str) : RENDER_PORT);
if (inet_aton(addr_str, &addr.sin_addr) == 0)
err_exit("invalid address: %s", addr_str);
int sock;
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
perr_exit("socket");
if (verbose)
printf("connect(%s, %d)\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
if (connect(sock, (const struct sockaddr *) &addr, sizeof(addr)) == -1)
perr_exit("connect(%s, %d)", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
FILE *fh = fdopen(sock, "w+");
if (!fh || ferror(fh))
perr_exit("fdopen");
setbuffer(fh, NULL, 0);
return fh;
}
int main (int argc, char **argv) {
int opt;
FILE *output = NULL, *remote = NULL;
int img_w = 256, img_h = 256;
while ((opt = getopt(argc, argv, "w:h:o:vr:")) != -1) {
switch(opt) {
case 'w' :
img_w = atoi(optarg);
break;
case 'h' :
img_h = atoi(optarg);
break;
case 'o' :
if (output)
err_exit("Only use -o once");
output = fopen(optarg, "w");
if (!output)
die(optarg);
break;
case 'v' :
verbose = 1;
break;
case 'r' :
if (remote)
err_exit("Only use -r once");
remote = open_remote(optarg);
break;
default :
err_exit("Usage: %s [-w img_w] [-h img_h] [-o output_file] [-v] [-r host[:port]]", argv[0]);
}
}
if (!output)
output = stdout;
if (remote) {
if (verbose)
fprintf(stderr, "Render [%dx%d] mandelbrot remotely\n", img_w, img_h);
render_remote(img_w, img_h, output, remote);
fclose(remote);
} else {
if (verbose)
fprintf(stderr, "Render [%dx%d] mandelbrot locally\n", img_w, img_h);
render_local(img_w, img_h, output);
}
fclose(output);
return 0;
}