X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fsonar.c;h=42bcdc8e7d6cc4ddb3d8afff039dff1535c00f2a;hp=da66865b01f5ccef35779f726cfc87cf2ef7a396;hb=4361b69d3178d7fc98d0388f9a223af6c2651aba;hpb=5f9c47ca98dd43d8f59b7c27d3fde6edfde4fe21 diff --git a/hacks/glx/sonar.c b/hacks/glx/sonar.c index da66865b..42bcdc8e 100644 --- a/hacks/glx/sonar.c +++ b/hacks/glx/sonar.c @@ -1,4 +1,4 @@ -/* sonar, Copyright (c) 1998-2011 Jamie Zawinski and Stephen Martin +/* sonar, Copyright (c) 1998-2015 Jamie Zawinski and Stephen Martin * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -43,14 +43,15 @@ * * It should be easy to extend this code to support other sorts of sensors. * Some ideas: + * * - search the output of "netstat" for the list of hosts to ping; * - plot the contents of /proc/interrupts; * - plot the process table, by process size, cpu usage, or total time; * - plot the logged on users by idle time or cpu usage. - * + * - plot IM contacts or Facebook friends and their last-activity times. */ -#define DEF_FONT "-*-lucidatypewriter-bold-r-normal-*-*-480-*-*-*-*-iso8859-1" +#define DEF_FONT "-*-courier-bold-r-normal-*-*-480-*-*-*-*-iso8859-1" #define DEF_SPEED "1.0" #define DEF_SWEEP_SIZE "0.3" #define DEF_FONT_SIZE "12" @@ -65,13 +66,18 @@ #define DEF_WOBBLE "True" #define DEF_DEBUG "False" +#include "thread_util.h" + #define DEFAULTS "*delay: 30000 \n" \ "*font: " DEF_FONT "\n" \ "*showFPS: False \n" \ "*wireframe: False \n" \ + "*texFontCacheSize: 300 \n" \ + THREAD_DEFAULTS_XLOCK # define refresh_sonar 0 +# define release_sonar 0 #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) @@ -88,6 +94,16 @@ #ifdef USE_GL /* whole file */ +/* #define TEST_ASYNC_NETDB 1 */ + +# if TEST_ASYNC_NETDB +# include "async_netdb.h" + +# include +# include +# include +# endif /* TEST_ASYNC_NETDB */ + typedef struct { double x,y,z; } XYZ; @@ -108,12 +124,18 @@ typedef struct { texture_font_data *texfont; + enum { MSG, RESOLVE, RUN } state; sonar_sensor_data *ssd; char *error; + char *desc; sonar_bogie *displayed; /* on screen and fading */ sonar_bogie *pending; /* returned by sensor, not yet on screen */ +# if TEST_ASYNC_NETDB + async_name_from_addr_t query0; + async_addr_from_name_t query1; +# endif } sonar_configuration; static sonar_configuration *sps = NULL; @@ -149,6 +171,7 @@ static XrmOptionDescRec opts[] = { { "+times", ".times", XrmoptionNoArg, "False" }, { "-wobble", ".wobble", XrmoptionNoArg, "True" }, { "+wobble", ".wobble", XrmoptionNoArg, "False" }, + THREAD_OPTIONS { "-debug", ".debug", XrmoptionNoArg, "True" }, }; @@ -191,7 +214,6 @@ draw_screen (ModeInfo *mi, Bool mesh_p, Bool sweep_p) if (wire && !(mesh_p || sweep_p)) return 0; - glPushAttrib (GL_ENABLE_BIT); glDisable (GL_TEXTURE_2D); glFrontFace (GL_CCW); @@ -314,7 +336,6 @@ draw_screen (ModeInfo *mi, Bool mesh_p, Bool sweep_p) glEnd(); } - glPopAttrib(); free (ring); return polys; @@ -333,10 +354,10 @@ draw_text (ModeInfo *mi, const char *string, GLfloat r, GLfloat th, char *string2 = strdup (string); char *token = string2; char *line; - GLfloat color[4]; if (size <= 0) /* if size not specified, draw in yellow with alpha */ { + GLfloat color[4]; color[0] = 1; color[1] = 1; color[2] = 0; @@ -350,7 +371,11 @@ draw_text (ModeInfo *mi, const char *string, GLfloat r, GLfloat th, while ((line = strtok (token, "\r\n"))) { - int w = texture_string_width (sp->texfont, line, &lh); + XCharStruct e; + int w, ascent, descent; + texture_string_metrics (sp->texfont, line, &e, &ascent, &descent); + w = e.width; + lh = ascent + descent; if (w > max_w) max_w = w; lines++; token = 0; @@ -383,9 +408,12 @@ draw_text (ModeInfo *mi, const char *string, GLfloat r, GLfloat th, token = string2; while ((line = strtok (token, "\r\n"))) { - int w = texture_string_width (sp->texfont, line, 0); + XCharStruct e; + int w; + texture_string_metrics (sp->texfont, line, &e, 0, 0); + w = e.width; glPushMatrix(); - glTranslatef ((max_w-w)/2, 0, 0); + glTranslatef ((max_w-w)/2, 0, polys * 4); /* 'polys' stops Z-fighting. */ if (wire) { @@ -429,13 +457,11 @@ draw_table (ModeInfo *mi) int th_steps = 36 * 4; /* same as in draw_screen */ static const GLfloat color[4] = {0.0, 0.0, 0.0, 1.0}; - static const GLfloat text[4] = {0.15, 0.15, 0.15, 1.0}; static const GLfloat spec[4] = {0.0, 0.0, 0.0, 1.0}; static const GLfloat shiny = 0.0; if (wire) return 0; - glPushAttrib (GL_ENABLE_BIT); glDisable (GL_TEXTURE_2D); glMaterialfv (GL_FRONT, GL_SPECULAR, spec); @@ -455,8 +481,21 @@ draw_table (ModeInfo *mi) polys++; } glEnd(); - glPopAttrib(); + return polys; +} + + +static int +draw_angles (ModeInfo *mi) +{ + int i; + int polys = 0; + + static const GLfloat text[4] = {0.15, 0.15, 0.15, 1.0}; + static const GLfloat spec[4] = {0.0, 0.0, 0.0, 1.0}; + + glMaterialfv (GL_FRONT, GL_SPECULAR, spec); glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, text); glTranslatef (0, 0, 0.01); for (i = 0; i < 360; i += 10) @@ -503,7 +542,7 @@ draw_bogies (ModeInfo *mi) /* called from sonar-sim.c and sonar-icmp.c */ sonar_bogie * -copy_bogie (sonar_sensor_data *ssd, const sonar_bogie *b) +sonar_copy_bogie (sonar_sensor_data *ssd, const sonar_bogie *b) { sonar_bogie *b2 = (sonar_bogie *) calloc (1, sizeof(*b2)); b2->name = strdup (b->name); @@ -523,7 +562,7 @@ copy_bogie (sonar_sensor_data *ssd, const sonar_bogie *b) /* called from sonar-icmp.c */ void -free_bogie (sonar_sensor_data *ssd, sonar_bogie *b) +sonar_free_bogie (sonar_sensor_data *ssd, sonar_bogie *b) { if (b->closure) ssd->free_bogie_cb (ssd, b->closure); @@ -546,7 +585,7 @@ delete_bogie (sonar_sensor_data *ssd, sonar_bogie *b, prev->next = b->next; else (*from_list) = b->next; - free_bogie (ssd, b); + sonar_free_bogie (ssd, b); break; } } @@ -573,7 +612,7 @@ copy_and_insert_bogie (sonar_sensor_data *ssd, sonar_bogie *b, } } - b = copy_bogie (ssd, b); + b = sonar_copy_bogie (ssd, b); b->next = *to_list; *to_list = b; } @@ -719,22 +758,22 @@ static void draw_startup_blurb (ModeInfo *mi) { sonar_configuration *sp = &sps[MI_SCREEN(mi)]; - const char *msg = (sp->error ? sp->error : "Resolving hosts..."); - static const GLfloat color[4] = {0, 1, 0, 1}; - if (!sp->error && ping_arg && !strcmp (ping_arg, "simulation")) - return; /* don't bother */ + if (sp->error) + { + const char *msg = sp->error; + static const GLfloat color[4] = {0, 1, 0, 1}; - glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color); - glTranslatef (0, 0, 0.3); - draw_text (mi, msg, 0, 0, 0, 30.0); + glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color); + glTranslatef (0, 0, 0.3); + draw_text (mi, msg, 0, 0, 0, 30.0); - /* only leave error message up for N seconds */ - if (sp->error && - sp->start_time + 4 < double_time()) - { - free (sp->error); - sp->error = 0; + /* only leave error message up for N seconds */ + if (sp->start_time + 6 < double_time()) + { + free (sp->error); + sp->error = 0; + } } } @@ -770,90 +809,29 @@ sonar_handle_event (ModeInfo *mi, XEvent *event) { sonar_configuration *sp = &sps[MI_SCREEN(mi)]; - if (event->xany.type == ButtonPress && - event->xbutton.button == Button1) - { - sp->button_down_p = True; - gltrackball_start (sp->trackball, - event->xbutton.x, event->xbutton.y, - MI_WIDTH (mi), MI_HEIGHT (mi)); - return True; - } - else if (event->xany.type == ButtonRelease && - event->xbutton.button == Button1) - { - sp->button_down_p = False; - return True; - } - else if (event->xany.type == ButtonPress && - (event->xbutton.button == Button4 || - event->xbutton.button == Button5 || - event->xbutton.button == Button6 || - event->xbutton.button == Button7)) - { - gltrackball_mousewheel (sp->trackball, event->xbutton.button, 10, - !!event->xbutton.state); - return True; - } - else if (event->xany.type == MotionNotify && - sp->button_down_p) - { - gltrackball_track (sp->trackball, - event->xmotion.x, event->xmotion.y, - MI_WIDTH (mi), MI_HEIGHT (mi)); - return True; - } + if (gltrackball_event_handler (event, sp->trackball, + MI_WIDTH (mi), MI_HEIGHT (mi), + &sp->button_down_p)) + return True; return False; } +static void free_sonar (ModeInfo *mi); ENTRYPOINT void init_sonar (ModeInfo *mi) { sonar_configuration *sp; - int wire = MI_IS_WIREFRAME(mi); - if (!sps) { - sps = (sonar_configuration *) - calloc (MI_NUM_SCREENS(mi), sizeof (sonar_configuration)); - if (!sps) { - fprintf(stderr, "%s: out of memory\n", progname); - exit(1); - } - } + MI_INIT (mi, sps, free_sonar); sp = &sps[MI_SCREEN(mi)]; sp->glx_context = init_GL(mi); reshape_sonar (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); clear_gl_error(); /* WTF? sometimes "invalid op" from glViewport! */ - if (!wire) - { - GLfloat pos[4] = {0.05, 0.07, 1.00, 0.0}; - GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0}; - GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0}; - GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0}; - - glEnable(GL_TEXTURE_2D); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - glEnable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - glShadeModel(GL_SMOOTH); - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glLightfv(GL_LIGHT0, GL_AMBIENT, amb); - glLightfv(GL_LIGHT0, GL_DIFFUSE, dif); - glLightfv(GL_LIGHT0, GL_SPECULAR, spc); - } - - sp->trackball = gltrackball_init (); + sp->trackball = gltrackball_init (False); sp->rot = make_rotator (0, 0, 0, 0, speed * 0.003, True); sp->texfont = load_texture_font (MI_DISPLAY(mi), "font"); @@ -882,8 +860,56 @@ init_sonar (ModeInfo *mi) sp->start_time = double_time (); sp->sweep_offset = random() % 60; sp->sweep_th = -1; + sp->state = MSG; +} + + +# ifdef TEST_ASYNC_NETDB + +# include + +static void _print_sockaddr (void *addr, socklen_t addrlen, FILE *stream) +{ + sa_family_t family = ((struct sockaddr *)addr)->sa_family; + char buf[256]; + switch (family) + { + case AF_INET: + fputs (inet_ntoa(((struct sockaddr_in *)addr)->sin_addr), stream); + break; + case AF_INET6: + inet_ntop(family, &((struct sockaddr_in6 *)addr)->sin6_addr, + buf, sizeof (buf)); + fputs (buf, stream); + break; + default: + abort(); + break; + } +} + +static void _print_error (int gai_error, int errno_error, FILE *stream) +{ + fputs (gai_error == EAI_SYSTEM ? strerror(errno_error) : gai_strerror(gai_error), stream); +} + +# if ASYNC_NETDB_USE_GAI + +static void _print_thread (pthread_t thread, FILE *stream) +{ +# ifdef __linux__ + fprintf (stream, "%#lx", thread); +# elif defined __APPLE__ && defined __MACH__ + fprintf (stream, "%p", thread); +# else + putc ('?', stream); +# endif } +# endif /* ASYNC_NETDB_USE_GAI */ + +# endif /* TEST_ASYNC_NETDB */ + static void init_sensor (ModeInfo *mi) @@ -895,20 +921,106 @@ init_sensor (ModeInfo *mi) if (!ping_arg || !*ping_arg || !strcmp(ping_arg, "default") || !!strcmp (ping_arg, "simulation")) - sp->ssd = init_ping (MI_DISPLAY (mi), &sp->error, ping_arg, - ping_timeout, resolve_p, times_p, debug_p); + /* sonar_init_ping() always disavows privs, even on failure. */ + sp->ssd = sonar_init_ping (MI_DISPLAY (mi), &sp->error, &sp->desc, + ping_arg, ping_timeout, resolve_p, times_p, + debug_p); + else + setuid(getuid()); /* Disavow privs if not pinging. */ - /* Disavow privs. This was already done in init_ping(), but - we might not have called that at all, so do it again. */ - setuid(getuid()); + sp->start_time = double_time (); /* for error message timing */ if (!sp->ssd) - sp->ssd = init_simulation (MI_DISPLAY (mi), &sp->error, - team_a_name, team_b_name, - team_a_count, team_b_count, - debug_p); + sp->ssd = sonar_init_simulation (MI_DISPLAY (mi), &sp->error, &sp->desc, + team_a_name, team_b_name, + team_a_count, team_b_count, + debug_p); if (!sp->ssd) abort(); + +# if TEST_ASYNC_NETDB + /* + For extremely mysterious reasons, setuid apparently causes + pthread_join(3) to deadlock. + A rough guess at the sequence of events: + 1. Worker thread is created. + 2. Worker thread exits. + 3. setuid(getuid()) is called. + 4. pthread_join is called slightly later. + + This may have something to do with glibc's use of SIGSETXID. + */ + + putc ('\n', stderr); + +# if !ASYNC_NETDB_USE_GAI + fputs ("Warning: getaddrinfo() was not available at compile time.\n", stderr); +# endif + + { + static const unsigned long addresses[] = + { + INADDR_LOOPBACK, + 0x00010203, + 0x08080808 + }; + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = htonl (addresses[random () % 3]); + + sp->query0 = async_name_from_addr_start (MI_DISPLAY (mi), (void *)&addr, + sizeof(addr)); + assert (sp->query0); + if (sp->query0) + { + fputs ("Looking up hostname from address: ", stderr); + _print_sockaddr (&addr, sizeof(addr), stderr); +# if ASYNC_NETDB_USE_GAI + fputs (" @ ", stderr); + _print_thread (sp->query0->io.thread, stderr); +# endif + putc ('\n', stderr); + } + + if (!(random () & 3)) + { + fputs ("Aborted hostname lookup (early)\n", stderr); + async_name_from_addr_cancel (sp->query0); + sp->query0 = NULL; + } + } + + { + static const char *const hosts[] = + { + "example.com", + "invalid", + "ip6-localhost" + }; + const char *host = hosts[random () % 3]; + + sp->query1 = async_addr_from_name_start (MI_DISPLAY(mi), host); + + assert (sp->query1); + + fprintf (stderr, "Looking up address from hostname: %s", host); +# if ASYNC_NETDB_USE_GAI + fputs (" @ ", stderr); + _print_thread (sp->query1->io.thread, stderr); +# endif + putc ('\n', stderr); + + if (!(random () & 3)) + { + fputs ("Aborted address lookup (early)\n", stderr); + async_addr_from_name_cancel (sp->query1); + sp->query1 = NULL; + } + } + + fflush (stderr); +# endif } @@ -918,6 +1030,7 @@ draw_sonar (ModeInfo *mi) sonar_configuration *sp = &sps[MI_SCREEN(mi)]; Display *dpy = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); + int wire = MI_IS_WIREFRAME(mi); if (!sp->glx_context) return; @@ -926,8 +1039,40 @@ draw_sonar (ModeInfo *mi) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (!wire) + { + GLfloat pos[4] = {0.05, 0.07, 1.00, 0.0}; + GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0}; + GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0}; + GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0}; + + glEnable(GL_TEXTURE_2D); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_NORMALIZE); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glShadeModel(GL_SMOOTH); + + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glLightfv(GL_LIGHT0, GL_AMBIENT, amb); + glLightfv(GL_LIGHT0, GL_DIFFUSE, dif); + glLightfv(GL_LIGHT0, GL_SPECULAR, spc); + } + glPushMatrix (); - { GLfloat s = 7; glScalef (s,s,s); } + glRotatef(current_device_rotation(), 0, 0, 1); + + { + GLfloat s = 7; + if (MI_WIDTH(mi) < MI_HEIGHT(mi)) + s *= (MI_WIDTH(mi) / (float) MI_HEIGHT(mi)); + glScalef (s,s,s); + } gltrackball_rotate (sp->trackball); @@ -967,8 +1112,37 @@ draw_sonar (ModeInfo *mi) glCallList (sp->grid_list); mi->polygon_count += sp->screen_polys; - if (! sp->ssd || sp->error) + glPushMatrix(); + mi->polygon_count += draw_angles (mi); /* angles */ + glPopMatrix(); + + if (sp->desc) /* local subnet */ + { + glPushMatrix(); + glTranslatef (0, 0, 0.00002); + mi->polygon_count += draw_text (mi, sp->desc, 1.35, M_PI * 0.75, 0, 10); + /* glRotatef (45, 0, 0, 1); */ + /* mi->polygon_count += draw_text (mi, sp->desc, 1.2, M_PI/2, 0, 10); */ + glPopMatrix(); + } + + if (sp->error) + sp->state = MSG; + + switch (sp->state) { + case MSG: /* Frame 1: get "Resolving Hosts" on screen. */ draw_startup_blurb(mi); + sp->state++; + break; + case RESOLVE: /* Frame 2: gethostbyaddr may take a while. */ + if (! sp->ssd) + init_sensor (mi); + sp->state++; + break; + case RUN: /* Frame N: ping away */ + sweep (sp); + break; + } glPopMatrix (); @@ -977,15 +1151,75 @@ draw_sonar (ModeInfo *mi) glXSwapBuffers(dpy, window); - if (! sp->ssd) - /* Just starting up. "Resolving hosts" text printed. Go stall. */ - init_sensor (mi); - else - sweep (sp); +# if TEST_ASYNC_NETDB + if(sp->query0 && async_name_from_addr_is_done (sp->query0)) + { + if (!(random () & 3)) + { + fputs ("Aborted hostname lookup (late)\n", stderr); + async_name_from_addr_cancel (sp->query0); + } + else + { + char *hostname = NULL; + int errno_error; + int gai_error = async_name_from_addr_finish (sp->query0, &hostname, + &errno_error); + + if(gai_error) + { + fputs ("Couldn't get hostname: ", stderr); + _print_error (gai_error, errno_error, stderr); + putc ('\n', stderr); + } + else + { + fprintf (stderr, "Got a hostname: %s\n", hostname); + free (hostname); + } + } + + sp->query0 = NULL; + } + + if(sp->query1 && async_addr_from_name_is_done (sp->query1)) + { + if (!(random () & 3)) + { + fputs ("Aborted address lookup (late)\n", stderr); + async_addr_from_name_cancel (sp->query1); + } + else + { + async_netdb_sockaddr_storage_t addr; + socklen_t addrlen; + int errno_error; + int gai_error = async_addr_from_name_finish (sp->query1, &addr, + &addrlen, &errno_error); + + if (gai_error) + { + fputs ("Couldn't get address: ", stderr); + _print_error (gai_error, errno_error, stderr); + putc ('\n', stderr); + } + else + { + fputs ("Got an address: ", stderr); + _print_sockaddr (&addr, addrlen, stderr); + putc ('\n', stderr); + } + } + + sp->query1 = NULL; + } + + fflush (stderr); +# endif /* TEST_ASYNC_NETDB */ } -ENTRYPOINT void -release_sonar (ModeInfo *mi) +static void +free_sonar (ModeInfo *mi) { #if 0 sonar_configuration *sp = &sps[MI_SCREEN(mi)];