static void *ihy_playing(void *data) { /* contains uncompressed data, (ihy_buffer_content *) */ t_buffer buffer = ((struct ihy_streaming_data *)data)->buffer; ihy_data *ihy = ((struct ihy_streaming_data *)data)->ihy; ao_device *audio_device; struct ihy_buffer_content *to_play; audio_device = ao_init_device(16, ihy->Channels, ihy->Frequency); /* we need to ensure that the other thread has added, * at least, 1 element */ while (buffer_isempty(buffer)) usleep(50000); while (!buffer_isempty(buffer)) { to_play = buffer_get(buffer); ao_play_samples(audio_device, to_play->samples, to_play->samplesSize); free(to_play->samples); free(to_play); /* hum quite dangerous */ } ao_close_device(audio_device); return NULL; }
int main(void) { initStartup(); buffer_put(&SerialData0.rx, 0); // sleep this! while (1) { if (!buffer_isempty(&SerialData0.rx)) { //if you've received some input then save it to the input if (uart0_peek_int() != input) { prevInput = input; input = uart0_fgetchar_int(&uart_str); } else buffer_get(&SerialData0.rx); // remove from buffer! } if (prevInput != input) { if (input != 0) { // if the hosts requests a readout if ((input & 0b00001000) == 0) //if you've not requested the rear pad then disable mux and it's decoder input PORTL = 0x00; if (firstOffRx == 0) {// if you were in sleep then get out ()might need to change this sleepSystemWake(); firstOffRx = 1; } uart0_fputchar_int(MAIN_PACKET_END_BYTE,&uart_str); //send the start packet id for (int i = 0; i < 5; i++) { // rx all requested sensors uint8_t tempInput = (input & (0b00000001 << i)); if (tempInput != 0) helperRetrieveSensor(tempInput); } } else if (firstOffRx == 1) // sleep here once and only once sleepSystem(); } } return 0; }
/** * Check if there is data in the buffer. */ static int meth_dirty(lua_State *L) { int res = 0; p_ssl ssl = (p_ssl) luaL_checkudata(L, 1, "SSL:Connection"); if (ssl->state != ST_SSL_CLOSED) res = !buffer_isempty(&ssl->buf) || SSL_pending(ssl->ssl); lua_pushboolean(L, res); return 1; }
/*-------------------------------------------------------------------------*\ * Return any data available in buffer, or get more data from transport layer * if buffer is empty \*-------------------------------------------------------------------------*/ static int buffer_get(p_buffer buf, const char **data, size_t *count) { int err = IO_DONE; p_io io = buf->io; p_timeout tm = buf->tm; if (buffer_isempty(buf)) { size_t got; err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); buf->first = 0; buf->last = got; } *count = buf->last - buf->first; *data = buf->data + buf->first; return err; }
int netstring_get (buffer_ref b, stralloc *sa, unsigned int *unread) { unsigned int written ; int ok = 1 ; int r ; if (!sa->s || (!sa->len && !*unread)) { char *x ; unsigned int n ; unsigned int len ; for (;;) { x = buffer_PEEK(b) ; n = byte_chr(x, buffer_len(b), ':') ; /* XXX: accepts :, as a valid netstring */ if (n >= ULONG_FMT) return (errno = EINVAL, -1) ; /* XXX: breaks on too many leading '0's */ if (n < buffer_len(b)) break ; r = buffer_fill(b) ; if (r == -1) return -1 ; if (!r) return (buffer_isempty(b) ? 0 : (errno = EPIPE, -1)) ; ok = 2 ; } if (n != uint_scan(x, &len)) return (errno = EINVAL, -1) ; if (!stralloc_readyplus(sa, len+1)) return -1 ; buffer_SEEK(b, n+1) ; *unread = len + 1 ; } written = sa->len ; r = buffer_getall(b, sa->s + sa->len, sa->len + *unread, &written) ; if (r <= 0) { *unread -= written - sa->len ; sa->len = written ; return r ? r : (errno = EINVAL, -1) ; } if (r == 2) ok = 2 ; sa->len += *unread ; *unread = 0 ; return (sa->s[--sa->len] == ',') ? ok : (errno = EINVAL, -1) ; }
static int meth_dirty(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); lua_pushboolean(L, !buffer_isempty(&tcp->buf)); return 1; }
/*-------------------------------------------------------------------------*\ * Skips a given number of bytes from read buffer. No data is read from the * transport layer \*-------------------------------------------------------------------------*/ static void buffer_skip(p_buffer buf, size_t count) { buf->received += count; buf->first += count; if (buffer_isempty(buf)) buf->first = buf->last = 0; }
static int meth_dirty(lua_State *L) { p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); lua_pushboolean(L, !buffer_isempty(&un->buf)); return 1; }
LIST * var_expand( LIST *prefix, const char *in, const char *end, LOL *lol, int cancopyin ) { BUFFER buff; const char *inp = in; int depth; size_t save_buffer_pos, ov_save_buffer_pos; int literal = 0; if( DEBUG_VAREXP ) printf( "expand '%.*s'\n", end - in, in ); /* This gets alot of cases: $(<) and $(>) */ if( end - in == 4 && in[0] == '$' && in[1] == leftParen && in[3] == rightParen ) { switch( in[2] ) { case '1': case '<': return list_copy( prefix, lol_get( lol, 0 ) ); case '2': case '>': return list_copy( prefix, lol_get( lol, 1 ) ); } } buffer_init( &buff ); /* Just try simple copy of in to out. */ while( in < end ) { char ch = *in++; buffer_addchar( &buff, ch ); if( ch == '$' && *in == leftParen ) goto expand; #ifdef OPT_EXPAND_LITERALS_EXT if( ch == '@' && *in == leftParen ) { literal = 1; goto expand; } if( ch == '@' && in[0] == '$' && in[1] == leftParen ) { ++in; literal = 1; goto expand; } #endif } /* No variables expanded - just add copy of input string to list. */ /* Cancopyin is an optimization: if the input was already a list */ /* item, we can use the copystr() to put it on the new list. */ /* Otherwise, we use the slower newstr(). */ buffer_putchar( &buff, 0 ); if( cancopyin ) { LIST *new_list = list_append( prefix, inp, 1 ); buffer_free( &buff ); return new_list; } else { LIST *new_list = list_append( prefix, buffer_ptr( &buff ), 0 ); buffer_free( &buff ); return new_list; } expand: /* * Input so far (ignore blanks): * * stuff-in-outbuf $(variable) remainder * ^ ^ * in end * Output so far: * * stuff-in-outbuf $ * ^ ^ * out_buf out * * * We just copied the $ of $(...), so back up one on the output. * We now find the matching close paren, copying the variable and * modifiers between the $( and ) temporarily into out_buf, so that * we can replace :'s with MAGIC_COLON. This is necessary to avoid * being confused by modifier values that are variables containing * :'s. Ugly. */ depth = 1; buffer_deltapos( &buff, -1 ); save_buffer_pos = buffer_pos( &buff ); in++; while( in < end && depth ) { char ch = *in++; buffer_addchar( &buff, ch ); if ( ch == leftParen ) { depth++; } else if ( ch == rightParen ) { depth--; } else { switch( ch ) { case ':': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_COLON ); break; case '[': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_LEFT ); break; case ']': buffer_deltapos( &buff, -1 ); buffer_addchar( &buff, MAGIC_RIGHT ); break; } } } /* Copied ) - back up. */ buffer_deltapos( &buff, -1 ); ov_save_buffer_pos = buffer_pos( &buff ); buffer_setpos( &buff, save_buffer_pos ); /* * Input so far (ignore blanks): * * stuff-in-outbuf $(variable) remainder * ^ ^ * in end * Output so far: * * stuff-in-outbuf variable * ^ ^ ^ * out_buf out ov * * Later we will overwrite 'variable' in out_buf, but we'll be * done with it by then. 'variable' may be a multi-element list, * so may each value for '$(variable element)', and so may 'remainder'. * Thus we produce a product of three lists. */ { LIST *variables = 0; LIST *remainder = 0; LISTITEM *vars; /* Recursively expand variable name & rest of input */ if( save_buffer_pos < ov_save_buffer_pos ) variables = var_expand( L0, buffer_posptr( &buff ), buffer_ptr( &buff ) + ov_save_buffer_pos, lol, 0 ); if( in < end ) remainder = var_expand( L0, in, end, lol, 0 ); /* Now produce the result chain */ /* For each variable name */ for( vars = list_first(variables); vars; vars = list_next( vars ) ) { LIST *value, *evalue = 0; LISTITEM* valueSliceStart = NULL; #ifdef OPT_EXPAND_LITERALS_EXT LIST *origvalue = 0; #endif char *colon; char *bracket; BUFFER varnamebuff; int sub1 = 0, sub2 = -1; VAR_EDITS edits; memset(&edits, 0, sizeof(VAR_EDITS)); if (leftParen == '{') { edits.empty.ptr = ""; edits.empty.len = 0; } /* Look for a : modifier in the variable name */ /* Must copy into varname so we can modify it */ buffer_init( &varnamebuff ); buffer_addstring( &varnamebuff, list_value(vars), strlen( list_value(vars) ) ); buffer_addchar( &varnamebuff, 0 ); if( ( colon = strchr( buffer_ptr( &varnamebuff ), MAGIC_COLON ) ) ) { *colon = '\0'; var_edit_parse( colon + 1, &edits ); } /* Look for [x-y] and [x-] subscripting */ /* sub1 is x (0 default) */ /* sub2 is length (-1 means forever) */ if( ( bracket = strchr( buffer_ptr( &varnamebuff ), MAGIC_LEFT ) ) ) { char *dash; if( ( dash = strchr( bracket + 1, '-' ) ) ) *dash = '\0'; sub1 = atoi( bracket + 1 ) - 1; if( !dash ) sub2 = 1; else if( !dash[1] || dash[1] == MAGIC_RIGHT ) sub2 = -1; else sub2 = atoi( dash + 1 ) - sub1; *bracket = '\0'; } /* Get variable value, specially handling $(<), $(>), $(n) */ #ifdef OPT_EXPAND_LITERALS_EXT if ( !literal ) #endif { const char* varname = buffer_ptr( &varnamebuff ); if( varname[0] == '<' && !varname[1] ) value = lol_get( lol, 0 ); else if( varname[0] == '>' && !varname[1] ) value = lol_get( lol, 1 ); else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] ) value = lol_get( lol, varname[0] - '1' ); else if ( edits.targetsetting ) { TARGET* t = bindtarget(edits.targetname.ptr); SETTINGS* settings = quicksettingslookup(t, varname); if (settings) value = list_copy(L0, settings->value); else value = L0; } else value = var_get( varname ); } #ifdef OPT_EXPAND_LITERALS_EXT else { origvalue = value = list_append( L0, buffer_ptr( &varnamebuff ), 0 ); } #endif /* The fast path: $(x) - just copy the variable value. */ /* This is only an optimization */ if( buffer_isempty( &buff ) && !bracket && !colon && in == end ) { prefix = list_copy( prefix, value ); buffer_free( &buff ); continue; } /* Handle start subscript */ valueSliceStart = list_first(value); while(sub1 > 0 && valueSliceStart) { sub1 -= 1; valueSliceStart = list_next(valueSliceStart); } /* Empty w/ :E=default? */ if( !valueSliceStart && (colon || leftParen == '{') && edits.empty.ptr ) { evalue = value = list_append( L0, edits.empty.ptr, 0 ); valueSliceStart = list_first(value); } #ifdef OPT_EXPAND_LITERALS_EXT if ( colon && edits.expandliteral ) { LOL lol; char const* string = list_value(list_first(value)); LIST *newvalue = var_expand( L0, string, string + strlen( string ), &lol, 0 ); if ( origvalue ) { list_free( origvalue ); origvalue = 0; } value = newvalue; valueSliceStart = list_first(value); sub2 = -1; } #endif #ifdef OPT_EXPAND_FILEGLOB_EXT if ( edits.wildcard ) { LIST *newl = L0; for( ; valueSliceStart; valueSliceStart = list_next( valueSliceStart ) ) { LIST *foundfiles = L0; fileglob* glob; /* Handle end subscript (length actually) */ if( sub2 >= 0 && --sub2 < 0 ) break; glob = fileglob_Create( list_value(valueSliceStart) ); while ( fileglob_Next( glob ) ) { foundfiles = list_append( foundfiles, fileglob_FileName( glob ) + edits.wildcard_remove_prepend.len, 0 ); } fileglob_Destroy( glob ); /* TODO: Efficiency: Just append to newl above? */ newl = list_copy( newl, foundfiles ); list_free( foundfiles ); } if ( origvalue ) { list_free( origvalue ); origvalue = 0; } value = newl; origvalue = value; valueSliceStart = list_first(value); } #endif /* For each variable value */ for( ; valueSliceStart; valueSliceStart = list_next( valueSliceStart ) ) { LISTITEM *rem; size_t save_buffer_pos; size_t end_buffer_pos; const char *valuestring; /* Handle end subscript (length actually) */ if( sub2 >= 0 && --sub2 < 0 ) break; /* Apply : mods, if present */ save_buffer_pos = buffer_pos( &buff ); valuestring = list_value(valueSliceStart); #ifdef OPT_EXPAND_BINDING_EXT if( colon && edits.expandbinding ) { SETTINGS *expandText; TARGET *t = bindtarget( valuestring ); expandText = quicksettingslookup( t, "EXPAND_TEXT" ); if ( expandText && list_first(expandText->value) ) { valuestring = list_value(list_first(expandText->value)); } else { if( t->binding == T_BIND_UNBOUND ) { t->boundname = search_using_target_settings( t, t->name, &t->time ); t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING; } valuestring = t->boundname; } } #endif if( colon && edits.filemods ) { var_edit_file( valuestring, &buff, &edits ); } else { buffer_addstring( &buff, valuestring, strlen( valuestring ) + 1 ); } buffer_setpos( &buff, save_buffer_pos ); if( colon && ( edits.upshift || edits.downshift ) ) var_edit_shift( buffer_posptr( &buff ), &edits ); #ifdef OPT_SLASH_MODIFIERS_EXT if( colon && ( edits.fslash || edits.bslash ) ) var_edit_slash( buffer_posptr( &buff ), &edits ); #endif #ifdef OPT_EXPAND_ESCAPE_PATH_EXT if ( colon && edits.escapepath ) { const char* ptr = buffer_posptr( &buff ); const char* endptr = ptr + strlen( ptr ); BUFFER escapebuff; buffer_init( &escapebuff ); save_buffer_pos = buffer_pos( &buff ); #ifdef NT while ( ptr != endptr && *ptr != ' ' && *ptr != '/' ) ++ptr; if (*ptr == ' ' || *ptr == '/' ) { buffer_addchar( &escapebuff, '"' ); buffer_addstring( &escapebuff, buffer_posptr( &buff ), endptr - buffer_posptr( &buff ) ); buffer_addchar( &escapebuff, '"' ); buffer_addchar( &escapebuff, 0 ); buffer_addstring( &buff, buffer_ptr( &escapebuff ), buffer_pos( &escapebuff ) ); } #else while ( ptr != endptr ) { if ( *ptr == ' ' || *ptr == '\\' || *ptr == leftParen || *ptr == rightParen || *ptr == '"' ) { buffer_addchar( &escapebuff, '\\' ); } buffer_addchar( &escapebuff, *ptr ); ++ptr; } buffer_addchar( &escapebuff, 0 ); buffer_addstring( &buff, buffer_ptr( &escapebuff ), buffer_pos( &escapebuff ) ); #endif buffer_setpos( &buff, save_buffer_pos ); buffer_free( &escapebuff ); } #endif /* Handle :J=joinval */ /* If we have more values for this var, just */ /* keep appending them (with the join value) */ /* rather than creating separate LIST elements. */ if( colon && edits.join.ptr && ( list_next( valueSliceStart ) || list_next( vars ) ) ) { buffer_setpos( &buff, buffer_pos( &buff ) + strlen( buffer_posptr( &buff ) ) ); buffer_addstring( &buff, edits.join.ptr, strlen( edits.join.ptr ) + 1 ); buffer_deltapos( &buff, -1 ); continue; } /* If no remainder, append result to output chain. */ if( in == end ) { prefix = list_append( prefix, buffer_ptr( &buff ), 0 ); continue; } /* For each remainder, append the complete string */ /* to the output chain. */ /* Remember the end of the variable expansion so */ /* we can just tack on each instance of 'remainder' */ save_buffer_pos = buffer_pos( &buff ); end_buffer_pos = strlen( buffer_ptr( &buff ) ); buffer_setpos( &buff, end_buffer_pos ); for( rem = list_first(remainder); rem; rem = list_next( rem ) ) { buffer_addstring( &buff, list_value(rem), strlen( list_value(rem) ) + 1 ); buffer_setpos( &buff, end_buffer_pos ); prefix = list_append( prefix, buffer_ptr( &buff ), 0 ); } buffer_setpos( &buff, save_buffer_pos ); } /* Toss used empty */ if( evalue ) list_free( evalue ); #ifdef OPT_EXPAND_LITERALS_EXT if ( origvalue ) list_free( origvalue ); #endif #ifdef OPT_EXPAND_INCLUDES_EXCLUDES_EXT if ( edits.includes_excludes ) { LIST *newl = L0; LISTITEM* l; LIST *origprefix = prefix; int hasInclude = 0; if ( !regexhash ) regexhash = hashinit( sizeof(regexdata), "regex" ); { LISTITEM *inex = list_first(edits.includes_excludes); while ( inex ) { char mod = list_value(inex)[0]; inex = list_next( inex ); if ( mod == 'I' ) { hasInclude = 1; } } } for (l = list_first(prefix) ; l; l = list_next( l ) ) { LISTITEM *inex = list_first(edits.includes_excludes); int remove = hasInclude; while ( inex ) { char mod = list_value(inex)[0]; regexp *re; regexdata data, *d = &data; inex = list_next( inex ); data.name = list_value(inex); if( !hashcheck( regexhash, (HASHDATA **)&d ) ) { d->re = jam_regcomp( list_value(inex) ); (void)hashenter( regexhash, (HASHDATA **)&d ); } re = d->re; inex = list_next( inex ); if ( mod == 'X' ) { if( jam_regexec( re, list_value(l) ) ) remove = 1; } else if ( mod == 'I' ) { if( jam_regexec( re, list_value(l) ) ) remove = 0; } } if ( !remove ) newl = list_append( newl, list_value(l), 1 ); } /* TODO: Efficiency: Just modify prefix? */ list_free( origprefix ); prefix = newl; } #endif //#ifdef OPT_EXPAND_LITERALS_EXT // buffer_free( &buff ); //#endif #ifdef OPT_EXPAND_INCLUDES_EXCLUDES_EXT list_free( edits.includes_excludes ); #endif } /* variables & remainder were gifts from var_expand */ /* and must be freed */ list_free( variables ); list_free( remainder ); if( DEBUG_VAREXP ) { printf( "expanded to " ); list_print( prefix ); printf( "\n" ); } buffer_free( &buff ); return prefix; } }
static int buffer_isnonempty (buffer *b) { return !buffer_isempty(b) ; }
int main(int argc, char *const *argv) { int c, /* control descriptor (stdin) */ s; /* socket descriptor (PuTTY) */ Buffer cbuf, /* control buffer */ pbuf, /* pty buffer */ sbuf; /* socket buffer */ DBUG_INIT_ENV("main",argv[0],"DBUG_OPTS"); #ifndef DBUG_OFF setvbuf(DBUG_FILE, 0, _IONBF, 0); #endif /* General steps: 1. connect to cygterm backend 2. create pty 3. fork child process (/bin/bash) 4. select on pty, cygterm backend forwarding pty data and messages */ if (argc < 4) { DBUG_PRINT("error", ("Too few arguments")); DBUG_RETURN(CthelperInvalidUsage); } DBUG_PRINT("startup", ("isatty: (%d,%d,%d)", isatty(STDIN_FILENO), isatty(STDOUT_FILENO), isatty(STDERR_FILENO))); DBUG_PRINT("startup", ( "cmdline: [%s] %s %s %s ...", argv[0], argv[1], argv[2], argv[3])); { extern char **environ; char **envp; for (envp = environ; *envp; envp++) DBUG_PRINT("startup", ("%s", *envp)); } /* It is not necessary to close all open descriptors. There are no * files inherited from the PuTTY process except standard input. */ #ifndef DEBUG close(STDERR_FILENO); #endif /* Duplicate c and open /dev/null as 0 so that 0 can mean "closed". */ c = dup(STDIN_FILENO); close(STDIN_FILENO); open("/dev/null", O_RDWR); /* Command line: * argv[1] = port number * argv[2] = terminal name * argv[3] = terminal characteristics string * Any remaining arguments are the command to execute. If there are no * other arguments, use the user's default login shell with a - prefix * for its argv[0]. */ /* cthelper command line parameters: cthelper PORT TERM ATTRS [COMMAND [ARGS]] PORT port number for PuTTY pty input data socket TERM name of terminal (set TERM environment variable) ATTRS a colon-separated list of terminal attributes See init_pty() for details. COMMAND Runs COMMAND with ARGS as child process. If COMMAND is not supplied, cthelper will run the user's login shell as specified in /etc/passwd specifying "-" for its argv[0] as typical. */ /* connect to cygterm */ { int ct_port = strtol(argv[1], 0, 0); #ifdef DEBUG if (ct_port == 0) { /* For debugging purposes, make the tty we are started * in the "socket". This allows to test cthelper without * putty.exe */ assert(isatty(STDOUT_FILENO)); raw(); atexit(restore); c = open("/dev/null", O_RDONLY); s = dup(STDOUT_FILENO); } else #endif if (ct_port <= 0) { DBUG_PRINT("startup", ("invalid port")); DBUG_RETURN(CthelperInvalidPort); } DBUG_PRINT("startup", ("connect cygterm")); if (0 > (s = connect_cygterm(ct_port))) { DBUG_PRINT("startup", ("connect_cygterm: bad")); DBUG_RETURN(CthelperConnectFailed); } DBUG_PRINT("startup", ("OK")); } /* initialize buffers */ DBUG_PRINT("startup", ("initialize buffers")); BUFFER_ALLOCA(cbuf, CTLBUF); BUFFER_ALLOCA(pbuf, PTOBUF); BUFFER_ALLOCA(sbuf, PTIBUF); /* set up signal handling */ signal(SIGCHLD, handle_sigchld); /* start child process */ if (0 > (t = setup_child(&child, argv[2], argv[3], argv + 4))) { DBUG_PRINT("startup", ("setup_child failed: %s", strerror(-t))); DBUG_RETURN(CthelperPtyforkFailure); } /* To explain what is happening here: * 's' is the socket between PuTTY and cthelper; it is read to get * input for the tty and written to display output from the pty. * 't' is the pseudo terminal; it is read to get pty input which is sent to * PuTTY and written to pass input from PuTTY to the pty. * 'c' is standard input, which is a one-way anonymous pipe from PuTTY. * It is read to receive special messages from PuTTY such as * terminal resize events. * * This is the flow of data through the buffers: * s => sbuf => t * t => pbuf => s * c => cbuf => process_message() * * When 't' is closed, we close(s) to signal PuTTY we are done. * When 's' is closed, we kill(child, HUP) to kill the child process. */ setnonblock(c); setnonblock(s); setnonblock(t); DBUG_PRINT("info", ("c==%d, s==%d, t==%d", c, s, t)); /* allow easy select() and FD_ISSET() stuff */ assert(0 < c && c < s && s < t); DBUG_PRINT("startup", ("starting select loop")); while (s || t) { int n = 0; fd_set r, w; DBUG_ENTER("select"); FD_ZERO(&r); FD_ZERO(&w); if (c && !buffer_isfull(cbuf)) { FD_SET(c, &r); n = c; } if (s && !buffer_isfull(sbuf)) { FD_SET(s, &r); n = s; } if (s && !buffer_isempty(pbuf)) { FD_SET(s, &w); n = s; } if (t && !buffer_isfull(pbuf)) { FD_SET(t, &r); n = t; } if (t && !buffer_isempty(sbuf)) { FD_SET(t, &w); n = t; } switch (n = select(n + 1, &r, &w, 0, 0)) { case -1: DBUG_PRINT("error", ("%s", strerror(errno))); if (errno != EINTR) { /* Something bad happened */ close(c); c = 0; close(s); s = 0; close(t); t = 0; } break; case 0: DBUG_PRINT("info", ("select timeout")); break; default: DBUG_PRINT("info", ("%d ready descriptors [[r==%lx,w==%lx]]", n, *(unsigned long *)&r, *(unsigned long *)&w)); if (FD_ISSET(c, &r)) { DBUG_ENTER("c=>cbuf"); switch (buffer_read(cbuf, c)) { case -1: DBUG_PRINT("error", ("error reading c: %s", strerror(errno))); if (errno == EINTR || errno == EWOULDBLOCK) break; /*FALLTHRU*/ case 0: /* PuTTY closed the message pipe */ DBUG_PRINT("io", ("c closed")); close(c); c = 0; break; default: DBUG_PRINT("io", ("cbuf => process_message()")); process_message(cbuf, t); break; } DBUG_LEAVE; if (!--n) break; } if (FD_ISSET(s, &r)) { DBUG_ENTER("s=>sbuf"); switch (buffer_read(sbuf, s)) { case -1: DBUG_PRINT("error", ("error reading s: %s", strerror(errno))); if (errno == EINTR || errno == EWOULDBLOCK) break; /*FALLTHRU*/ case 0: /* PuTTY closed the socket */ DBUG_PRINT("io", ("s closed")); close(s); s = 0; break; default: FD_SET(t, &w); break; } DBUG_LEAVE; if (!--n) break; } if (FD_ISSET(t, &r)) { DBUG_ENTER("t=>pbuf"); switch (buffer_read(pbuf, t)) { case -1: DBUG_PRINT("error", ("error reading t: %s", strerror(errno))); if (errno == EINTR || errno == EWOULDBLOCK) break; /*FALLTHRU*/ case 0: /* pty closed */ DBUG_PRINT("io", ("t closed")); if (!FD_ISSET(t, &w)) { close(t); t = 0; } break; default: FD_SET(s, &w); break; } DBUG_LEAVE; if (!--n) break; } if (FD_ISSET(t, &w)) { DBUG_ENTER("sbuf=>t"); switch (buffer_write(sbuf, t)) { case -1: DBUG_PRINT("error", ("error writing t: %s", strerror(errno))); if (errno == EINTR || errno == EWOULDBLOCK) break; /*FALLTHRU*/ case 0: /* pty closed */ DBUG_PRINT("io", ("t closed")); close(t); t = 0; break; } DBUG_LEAVE; if (!--n) break; } if (FD_ISSET(s, &w)) { DBUG_ENTER("pbuf=>s"); switch (buffer_write(pbuf, s)) { case -1: DBUG_PRINT("error", ("error writing s: %s", strerror(errno))); if (errno == EINTR || errno == EWOULDBLOCK) break; /*FALLTHRU*/ case 0: /* PuTTY closed the socket */ DBUG_PRINT("io", ("s closed")); close(s); s = 0; break; } DBUG_LEAVE; if (!--n) break; } DBUG_PRINT("info", ("[[n==%d,r==%lx,w==%lx]]", n, *(unsigned long *)&r, *(unsigned long *)&w)); assert(n == 0); break; } if (child_signalled) check_child(); if (!t && buffer_isempty(pbuf)) { DBUG_PRINT("info", ("shutdown socket")); shutdown(s, SHUT_WR); } if (!s && buffer_isempty(sbuf) && child_alive()) { DBUG_PRINT("sig", ("kill child")); kill(child, SIGHUP); /* handle_sigchld() will close(t) */ } DBUG_LEAVE; } DBUG_PRINT("info", ("end of select loop")); /* ensure child process killed */ /* XXX I'm not sure if all of this is necessary, but it probably won't * hurt anything. */ if (child_alive() && sleep(1) == 0) { DBUG_PRINT("sig", ("waiting for child")); waitpid(child, 0, WNOHANG); } DBUG_PRINT("info", ("goodbye")); if (exit_status == 111) DBUG_RETURN(CthelperExecFailure); DBUG_RETURN(EXIT_SUCCESS); }