Skip to content
Snippets Groups Projects
kiraserver.cc 36.3 KiB
Newer Older
   *		num (32-bit int),
   *		color (16-bit short).
   * group and type fields shouldn't need swapping,
   * assuming the compiler packs bytes into a word in increasing
   * address order.  Seems safe.
   */
    for(i = 0, wp = (int *)st; i < 10; i++)
	wp[i] = htonl(wp[i]);
    st->color = htons(st->color);
  }
}
#else
#define  starswap(x)  /*nothing*/
#endif /*!WORDS_BIGENDIAN*/

static struct logTmap {
	float logT;
	unsigned short rgb565;
} tmap[] = {
//  Adapted from Mitchell Charity's web page on black body RGB colors,
//   http://www.vendian.org/mncharity/dir3/blackbody/
  3.000, 0xf9c0,  3.079, 0xfa80,  3.204, 0xfb80,  3.301, 0xfc42,
  3.380, 0xfce7,  3.477, 0xfdad,  3.556, 0xfe31,  3.643, 0xfed6,
  3.716, 0xff5a,  3.792, 0xffbe,  3.869, 0xef7f,  3.944, 0xdf1f,
  4.017, 0xcedf,  4.093, 0xbe9f,  4.164, 0xb67f,  4.236, 0xae5f,
  4.310, 0xae3f,  4.380, 0xa61f,  4.450, 0xa5ff,
};

static unsigned short logT2rgb565(float logT) {
    int i;
    for(i = 0; i < COUNT(tmap)-1 && logT > tmap[i].logT; i++)
	;
    return tmap[i].rgb565;
}
static double sx=0, sy=0, sz=0, smass=0;
static int nspecks;
static int has_tfm;
static Point pmin, pmax;
static Matrix pT;

static void report( FILE *outf, struct dyndata *dyn, struct stuff *st )
{
    double tmin, tmax;
    kira_get_trange( &st->dyn, st, &tmin, &tmax );
    fprintf(outf, "time %lg  in  %lg .. %lg\n",
	curstate.realtime, tmin, tmax);
    fprintf(outf, "nspecks %d\n", nspecks);
    if(smass > 0) {
	fprintf(outf, "CM %lg %lg %lg\n", sx/smass, sy/smass, sz/smass);
	fprintf(outf, "bbox center %g %g %g  radius %g %g %g\n",
	    .5*(pmax.x[0]+pmin.x[0]), .5*(pmax.x[1]+pmin.x[1]), .5*(pmax.x[2]+pmin.x[2]),
	    .5*(pmax.x[0]-pmin.x[0]), .5*(pmax.x[1]-pmin.x[1]), .5*(pmax.x[2]-pmin.x[2]));
	Point cen;
	kira_get_center( &cen, dyn, st );
	fprintf(outf, "Center %g %g %g", cen.x[0],cen.x[1],cen.x[2]);
	if(has_tfm) {
	    Point wcen;
	    vtfmpoint( &wcen, &cen, &pT );
	    fprintf(outf, " -> %g %g %g", wcen.x[0],wcen.x[1],wcen.x[2]);
	}
	fprintf(outf, "\n");
    }
    fprintf(outf, "transformation: out = in");
    if(curstate.turnrate != 0)
	fprintf(outf, " * %cRotation(%g*(time-%g))",
		curstate.axis, curstate.turnrate, curstate.turntime0);
    if(curstate.has_T0) {
	float *fp = curstate.T0.m;
	fprintf(outf, " * [%g %g %g %g  %g %g %g %g  %g %g %g %g  %g %g %g %g]",
		fp[0],fp[1],fp[2],fp[3],
		fp[4],fp[5],fp[6],fp[7],
		fp[8],fp[9],fp[10],fp[11],
		fp[12],fp[13],fp[14],fp[15]);
    }
    else if(curstate.turnrate == 0)
	fprintf(outf, " (identity transform)");
    fprintf(outf, "\n");
    fprintf(outf, "group %d  type %d\n", curstate.group, curstate.type);
}

float specklum( struct speck *sp ) {
    return (curstate.masslum != 0) ? sp->val[SPECK_MASS]*sp->val[SPECK_MASS]*sp->val[SPECK_MASS]*curstate.masslum :
				     sp->val[SPECK_LUM];
}

int serveonce(char *req, FILE *outf)
{
    int as_sdb = 0, as_speck = 0;
    Point p;
    db_star star;
    char *cp;
    struct stuff *st = curstate.st;

    nspecks=0;
    sx = sy = sz = smass = 0;

    pmin.x[0]=pmin.x[1]=pmin.x[2] = 1e20;
    pmax.x[0]=pmax.x[1]=pmax.x[2] = -1e20;

    if(curstate.verbose)
	fprintf(stdout, "REQ: %s\n", req);

    if(outf == NULL || req == NULL) {
	msg("kira server: get lost!");
	if(outf) fclose(outf);
	return 0;
    }

    if(strstr(req, "sdb"))  as_sdb = 1;
    else if(strstr(req, "speck")) as_speck = 1;

    char *eqp;
    for(eqp = req; (eqp = strchr(eqp, '=')) != NULL; ) {
	char *optp, *argp;
	for(optp = eqp; isalpha(optp[-1]); optp--)
	    ;
	argp = eqp+1;
	cp = strpbrk(argp, ";&");
	if(cp) {
	    eqp = cp+1;
	    *cp = '\0';
	}
	scanopt( optp, argp );
	if(cp == NULL) break;
    }

    memset(&star, 0, sizeof(star));

    star.group = curstate.group;
    star.type = curstate.type;

    struct specklist *sl;
    sl = kira_get_parti( &st->dyn, st, curstate.realtime );

    if(sl == NULL)
	return 0;

    has_tfm = curstate.has_T0 || curstate.turnrate != 0;
    if(curstate.turnrate != 0) {
	Matrix Trot;
	mrotation( &Trot, curstate.turnrate * (curstate.realtime - curstate.turntime0), curstate.axis );
	if(curstate.has_T0) {
	    mmmul( &pT, &Trot, &curstate.T0 );
    for(int i = 0; i < sl->nspecks; i++) {
	struct speck *sp = NextSpeck(sl->specks, sl, i);
	if(sp->val[SPECK_NCLUMP] < 0)
	    continue;
	nspecks++;
	Point vel, tvel;
	vel.x[0] = sp->val[SPECK_SEPVEC] * curstate.dt;
	vel.x[1] = sp->val[SPECK_SEPVEC+1] * curstate.dt;
	vel.x[2] = sp->val[SPECK_SEPVEC+2] * curstate.dt;
	    vtfmpoint( &p, &sp->p, &pT );
	    vtfmpoint( &tvel, &vel, &pT );
	    vel = tvel;
	} else {
	    p = sp->p;
	}
	if(as_sdb) {
	    star.x = p.x[0];
	    star.y = p.x[1];
	    star.z = p.x[2];
	    star.dx = vel.x[0];			// Use velocity,
	    star.dy = vel.x[1];			// held in SEPVEC
	    star.dz = vel.x[2];			// for leaf nodes.
	    star.magnitude = curstate.mag0 - .921 * logf( specklum(sp) );
	    if(curstate.colorscale >= 0) {
		star.color = (unsigned short) (curstate.colorscale * sp->val[SPECK_TLOG]);
	    } else {
		/* packed rgb565 */
		star.color = logT2rgb565( sp->val[SPECK_TLOG] );
	    }
	    star.num = (int) sp->val[SPECK_ID];
	    wrote = fwrite(&star, sizeof(star), 1, outf);
	    wrote = fprintf(outf, "%g %g %g %g %g %g\n",
		specklum(sp), sp->val[SPECK_TLOG], sp->val[SPECK_ID]);
	} else {
	    double m = sp->val[SPECK_MASS];
	    sx += p.x[0]*m;
	    sy += p.x[1]*m;
	    sz += p.x[2]*m;
	    smass += m;
	    if(pmin.x[0] > p.x[0]) pmin.x[0] = p.x[0];
	    if(pmin.x[1] > p.x[1]) pmin.x[1] = p.x[1];
	    if(pmin.x[2] > p.x[2]) pmin.x[2] = p.x[2];
	    if(pmax.x[0] < p.x[0]) pmax.x[0] = p.x[0];
	    if(pmax.x[1] < p.x[1]) pmax.x[1] = p.x[1];
	    if(pmax.x[2] < p.x[2]) pmax.x[2] = p.x[2];
	if(wrote < 0)			/* SIGPIPE? Anyway, quit writing. */
	    break;
	report( outf, &st->dyn, st );
    }
    if(curstate.verbose) {
	char *cp = strchr(req, '\n');
	if(cp) *cp = '\0';
	fprintf(stdout, "REQ: %s\n", req);
	report( stdout, &st->dyn, st );
	fflush(stdout);
}

int serverlisten( int port ) {
    struct sockaddr_in asin;
    static int one = 1;
    int lsock;

    memset(&asin, 0, sizeof(asin));
    asin.sin_family = AF_INET;
    asin.sin_port = htons(port);
    asin.sin_addr.s_addr = INADDR_ANY;

    lsock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    if(lsock < 0) {
	perror("socket");
	return -1;
    }
    setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    if(bind(lsock, (struct sockaddr *)&asin, sizeof(asin)) < 0) {
	perror("listen");
	return -1;
    }
    return lsock;
}

void serverloop( int lsock ) {
    for(;;) {
	struct sockaddr_in from;
	FILE *inf, *outf;
	char req[1280];
	
#if sgi
	int fromlen = sizeof(from);
#else
	unsigned int fromlen = sizeof(from);
	int s = accept(lsock, (struct sockaddr *)&from, &fromlen);
	if(s < 0) {
	    if(errno == EINTR)
		continue;
	    perror("accept");
	    return;
	}
	inf = fdopen(s, "r");
	if(fgets(req, sizeof(req), inf) == NULL) {
	    perror("fgets");
	} else {
	    outf = fdopen(s, "w");
	    do {
		serveonce( req, outf );
		fflush(outf);
	    } while(fgets(req, sizeof(req), inf) != NULL);
	    fclose(outf);
	}
	fclose(inf);
	close(s);
    }
}


main(int argc, char *argv[])
{
    static struct stuff tst;
    curstate.st = &tst;
    int c;
    char opt[8];

    progname = argv[0];

    curstate.colorscale = -1;
    curstate.has_T0 = 0;
    curstate.port = 3400;

    while((c = getopt(argc, argv, "T:r:t:y:g:m:c:o:p:v:iP")) != EOF) {
	opt[0] = c;
	opt[1] = '\0';
	if(c == 'y') strcpy(opt, "type");
	scanopt( opt, optarg );
    }
    if(optind != argc-1) {
	fprintf(stderr, "Usage: %s [options] file.kira\n\
Options:\n\
   -t time\n\
   -r <axis><degreespertime>[@time0]  Timed rotation about axis 'x'/'y'/'z'\n\
   -T 16-numbers   outcoords = kira * rotation(time) * tfm\n\
   -y sdbtype\n\
   -g group\n\
   -m mag0         sdb mag = mag0 - log(lum)/(log(100)/5)\n\
   -M masslum	   if nonzero, ignore bogus lum; use mass**3 * masslum instead.\n\
   -c colorscale   sdb color = log10(T)*colorscale; -c -1 => RGB565 (default)\n\
   -o treestyle(1 vs 2) (default -o 2 for create_interpolated_tree2)\n\
   -p portno	   listen for HTTP connections on that TCP port\n\
   -v verbose(0 vs 1) server logs requests to its own stdout\n\
   -i		   read from stdin, write to stdout (else be a network server)\n\

    /* Ignore SIGPIPE signals -- don't crash if a caller disconnects. */
    signal(SIGPIPE, SIG_IGN);

    if(curstate.use_stdin) {
	msg("Reading %s", argv[optind]);
	kira_open( &curstate.st->dyn, curstate.st, argv[optind], curstate.verbose ? KIRA_VERBOSE : 0 );
	int eofs = 0;
	char req[512];
	fprintf(stderr, "Type  ?  for help\n");
	for(;;) {
	    fprintf(stderr, "\n>> ");
	    if(fgets(req, sizeof(req), stdin) == NULL) {
		if(++eofs >= 3) break;	/* quit if 3 successive EOFs */
		continue;
	    } else {
		eofs = 0;
	    }

	    if(req[0] == 'q')
		break;

	    if(req[0] == '?' || req[0] == 'h') {
		printf("Usage:  each line of input yields one starlab lookup,\n\
after applying all options given on that line.  Unchanged settings persist.\n\
Options take the form <keyletter>=<value> and may be separated by \"&\" or \";\"\n\
  t=<time>   simulation time\n\
  o=<treestyle>  o=1 => create_interpolated_tree, o=2 => ...tree2.  Default o=2.\n\
  T=<16-numbers> apply 4x4 transformation\n\
  speck	     dump ASCII specks (default just summary information)\n\
  q          quit\n\
");
	    } else {
		serveonce( req, stdout );
	    }
	}
    } else {
	/* be a network server */

	msg("Listening on port %d", curstate.port);
	int lsock = serverlisten( curstate.port );
	if(lsock < 0)
	    exit(1);
	msg("Reading %s", argv[optind]);
	kira_open( &curstate.st->dyn, curstate.st, argv[optind], curstate.verbose ? KIRA_VERBOSE : 0 );
	msg("Ready.");
	serverloop( lsock );
    }