/* * Free an entire 'struct conf_entry' and its dynamic data. */ static void free_entry(struct conf_entry *entry) { free_key(&entry->key); free_value(&entry->value, valuetypes[entry->key.primary]); sfree(entry); } Conf *conf_new(void) { Conf *conf = snew(struct conf_tag); conf->tree = newtree234(conf_cmp); return conf; } static void conf_clear(Conf *conf) { struct conf_entry *entry; while ((entry = delpos234(conf->tree, 0)) != NULL) free_entry(entry); } void conf_free(Conf *conf) { conf_clear(conf);
indexdata *make_index(void) { indexdata *ret = snew(indexdata); ret->tags = newtree234(compare_tags); ret->entries = newtree234(compare_entries); return ret; }
void sk_init(void) { sktree = newtree234(cmpfortree); }
/* * Reads a single file (ie until get() returns EOF) */ static void read_file(paragraph *** ret, input * in, indexdata * idx) { token t; paragraph par; word wd, **whptr, **idximplicit; tree234 *macros; wchar_t utext[2], *wdtext; int style, spcstyle; int already; int iswhite, seenwhite; int type; struct stack_item { enum { stack_nop = 0, /* do nothing (for error recovery) */ stack_ualt = 1, /* \u alternative */ stack_style = 2, /* \e, \c, \cw */ stack_idx = 4, /* \I, \i, \ii */ stack_hyper = 8, /* \W */ stack_quote = 16, /* \q */ } type; word **whptr; /* to restore from \u alternatives */ word **idximplicit; /* to restore from \u alternatives */ } *sitem; stack parsestk; word *indexword=NULL, *uword=NULL, *iword=NULL; word *idxwordlist; rdstring indexstr; int index_downcase=0, index_visible=0, indexing=0; const rdstring nullrs = { 0, 0, NULL }; wchar_t uchr; t.text = NULL; macros = newtree234(macrocmp); already = FALSE; /* * Loop on each paragraph. */ while (1) { int start_cmd = c__invalid; par.words = NULL; par.keyword = NULL; whptr = &par.words; /* * Get a token. */ if (!already) { dtor(t), t = get_token(in); } already = FALSE; if (t.type == tok_eof) break; /* * Parse code paragraphs separately. */ if (t.type == tok_cmd && t.cmd == c_c && !isbrace(in)) { par.type = para_Code; par.fpos = t.pos; while (1) { dtor(t), t = get_codepar_token(in); wd.type = word_WeakCode; wd.breaks = FALSE; /* shouldn't need this... */ wd.text = ustrdup(t.text); wd.alt = NULL; wd.fpos = t.pos; addword(wd, &whptr); dtor(t), t = get_token(in); if (t.type == tok_white) { /* * The newline after a code-paragraph line */ dtor(t), t = get_token(in); } if (t.type == tok_eop || t.type == tok_eof) break; else if (t.type != tok_cmd || t.cmd != c_c) { error(err_brokencodepara, &t.pos); addpara(par, ret); while (t.type != tok_eop) /* error recovery: */ dtor(t), t = get_token(in); /* eat rest of paragraph */ goto codeparabroken; /* ick, but such is life */ } } addpara(par, ret); codeparabroken: continue; } while (t.type == tok_cmd && macrolookup(macros, in, t.text, &t.pos)) { dtor(t), t = get_token(in); } /* * This token begins a paragraph. See if it's one of the * special commands that define a paragraph type. * * (note that \# is special in a way, and \nocite takes no * text) */ par.type = para_Normal; if (t.type == tok_cmd) { int needkw=0; int is_macro = FALSE; par.fpos = t.pos; switch (t.cmd) { default: needkw = -1; break; case c__invalid: error(err_badparatype, t.text, &t.pos); needkw = 4; break; case c__comment: if (isbrace(in)) break; /* `\#{': isn't a comment para */ do { dtor(t), t = get_token(in); } while (t.type != tok_eop && t.type != tok_eof); continue; /* next paragraph */ /* * `needkw' values: * * 1 -- exactly one keyword * 2 -- at least one keyword * 4 -- any number of keywords including zero * 8 -- at least one keyword and then nothing else * 16 -- nothing at all! no keywords, no body * 32 -- no keywords at all */ case c_A: needkw = 2; par.type = para_Appendix; break; case c_B: needkw = 2; par.type = para_Biblio; break; case c_BR: needkw = 1; par.type = para_BR; start_cmd = c_BR; break; case c_C: needkw = 2; par.type = para_Chapter; break; case c_H: needkw = 2; par.type = para_Heading; par.aux = 0; break; case c_IM: needkw = 2; par.type = para_IM; start_cmd = c_IM; break; case c_S: needkw = 2; par.type = para_Subsect; par.aux = t.aux; break; case c_U: needkw = 32; par.type = para_UnnumberedChapter; break; /* For \b and \n the keyword is optional */ case c_b: needkw = 4; par.type = para_Bullet; break; case c_n: needkw = 4; par.type = para_NumberedList; break; case c_cfg: needkw = 8; par.type = para_Config; start_cmd = c_cfg; break; case c_copyright: needkw = 32; par.type = para_Copyright; break; case c_define: is_macro = TRUE; needkw = 1; break; /* For \nocite the keyword is _everything_ */ case c_nocite: needkw = 8; par.type = para_NoCite; break; case c_preamble: needkw = 32; par.type = para_Preamble; break; case c_rule: needkw = 16; par.type = para_Rule; break; case c_title: needkw = 32; par.type = para_Title; break; case c_versionid: needkw = 32; par.type = para_VersionID; break; } if (needkw > 0) { rdstring rs = { 0, 0, NULL }; int nkeys = 0; filepos fp; /* Get keywords. */ dtor(t), t = get_token(in); fp = t.pos; while (t.type == tok_lbrace) { /* This is a keyword. */ nkeys++; /* FIXME: there will be bugs if anyone specifies an * empty keyword (\foo{}), so trap this case. */ while (dtor(t), t = get_token(in), t.type == tok_word || t.type == tok_white || (t.type == tok_cmd && t.cmd == c__nbsp) || (t.type == tok_cmd && t.cmd == c__escaped)) { if (t.type == tok_white || (t.type == tok_cmd && t.cmd == c__nbsp)) rdadd(&rs, ' '); else rdadds(&rs, t.text); } if (t.type != tok_rbrace) { error(err_kwunclosed, &t.pos); continue; } rdadd(&rs, 0); /* add string terminator */ dtor(t), t = get_token(in); /* eat right brace */ } rdadd(&rs, 0); /* add string terminator */ /* See whether we have the right number of keywords. */ if ((needkw & 48) && nkeys > 0) error(err_kwillegal, &fp); if ((needkw & 11) && nkeys == 0) error(err_kwexpected, &fp); if ((needkw & 5) && nkeys > 1) error(err_kwtoomany, &fp); if (is_macro) { /* * Macro definition. Get the rest of the line * as a code-paragraph token, repeatedly until * there's nothing more left of it. Separate * with newlines. */ rdstring macrotext = { 0, 0, NULL }; while (1) { dtor(t), t = get_codepar_token(in); if (macrotext.pos > 0) rdadd(¯otext, L'\n'); rdadds(¯otext, t.text); dtor(t), t = get_token(in); if (t.type == tok_eop) break; } macrodef(macros, rs.text, macrotext.text, fp); continue; /* next paragraph */ } par.keyword = rdtrim(&rs); /* Move to EOP in case of needkw==8 or 16 (no body) */ if (needkw & 24) { /* We allow whitespace even when we expect no para body */ while (t.type == tok_white) dtor(t), t = get_token(in); if (t.type != tok_eop && t.type != tok_eof && (start_cmd == c__invalid || t.type != tok_cmd || t.cmd != start_cmd)) { error(err_bodyillegal, &t.pos); /* Error recovery: eat the rest of the paragraph */ while (t.type != tok_eop && t.type != tok_eof && (start_cmd == c__invalid || t.type != tok_cmd || t.cmd != start_cmd)) dtor(t), t = get_token(in); } if (t.type == tok_cmd) already = TRUE; /* inhibit get_token at top of loop */ addpara(par, ret); continue; /* next paragraph */ } } } /* * Now read the actual paragraph, word by word, adding to * the paragraph list. * * Mid-paragraph commands: * * \K \k * \c \cw * \e * \i \ii * \I * \u * \W * \date * \\ \{ \} */ parsestk = stk_new(); style = word_Normal; spcstyle = word_WhiteSpace; indexing = FALSE; seenwhite = TRUE; while (t.type != tok_eop && t.type != tok_eof) { iswhite = FALSE; already = FALSE; /* Handle implicit paragraph breaks after \IM, \BR etc */ if (start_cmd != c__invalid && t.type == tok_cmd && t.cmd == start_cmd) { already = TRUE; /* inhibit get_token at top of loop */ break; } if (t.type == tok_cmd && t.cmd == c__escaped) { t.type = tok_word; /* nice and simple */ t.aux = 0; /* even if `\-' - nonbreaking! */ } if (t.type == tok_cmd && t.cmd == c__nbsp) { t.type = tok_word; /* nice and simple */ sfree(t.text); t.text = ustrdup(L" "); /* text is ` ' not `_' */ t.aux = 0; /* (nonbreaking) */ } switch (t.type) { case tok_white: if (whptr == &par.words) break; /* strip whitespace at start of para */ wd.text = NULL; wd.type = spcstyle; wd.alt = NULL; wd.aux = 0; wd.fpos = t.pos; wd.breaks = FALSE; /* * Inhibit use of whitespace if it's (probably the * newline) before a repeat \IM / \BR type * directive. */ if (start_cmd != c__invalid) { dtor(t), t = get_token(in); already = TRUE; if (t.type == tok_cmd && t.cmd == start_cmd) break; } if (indexing) rdadd(&indexstr, ' '); if (!indexing || index_visible) addword(wd, &whptr); if (indexing) addword(wd, &idximplicit); iswhite = TRUE; break; case tok_word: if (indexing) rdadds(&indexstr, t.text); wd.type = style; wd.alt = NULL; wd.aux = 0; wd.fpos = t.pos; wd.breaks = t.aux; if (!indexing || index_visible) { wd.text = ustrdup(t.text); addword(wd, &whptr); } if (indexing) { wd.text = ustrdup(t.text); addword(wd, &idximplicit); } break; case tok_lbrace: error(err_unexbrace, &t.pos); /* Error recovery: push nop */ sitem = mknew(struct stack_item); sitem->type = stack_nop; stk_push(parsestk, sitem); break; case tok_rbrace: sitem = stk_pop(parsestk); if (!sitem) error(err_unexbrace, &t.pos); else { if (sitem->type & stack_ualt) { whptr = sitem->whptr; idximplicit = sitem->idximplicit; } if (sitem->type & stack_style) { style = word_Normal; spcstyle = word_WhiteSpace; } if (sitem->type & stack_idx ) { indexword->text = ustrdup(indexstr.text); if (index_downcase) ustrlow(indexword->text); indexing = FALSE; rdadd(&indexstr, L'\0'); index_merge(idx, FALSE, indexstr.text, idxwordlist); sfree(indexstr.text); } if (sitem->type & stack_hyper) { wd.text = NULL; wd.type = word_HyperEnd; wd.alt = NULL; wd.aux = 0; wd.fpos = t.pos; wd.breaks = FALSE; if (!indexing || index_visible) addword(wd, &whptr); if (indexing) addword(wd, &idximplicit); } if (sitem->type & stack_quote) { wd.text = NULL; wd.type = toquotestyle(style); wd.alt = NULL; wd.aux = quote_Close; wd.fpos = t.pos; wd.breaks = FALSE; if (!indexing || index_visible) addword(wd, &whptr); if (indexing) { rdadd(&indexstr, L'"'); addword(wd, &idximplicit); } } } sfree(sitem); break; case tok_cmd: switch (t.cmd) { case c__comment: /* * In-paragraph comment: \#{ balanced braces } * * Anything goes here; even tok_eop. We should * eat whitespace after the close brace _if_ * there was whitespace before the \#. */ dtor(t), t = get_token(in); if (t.type != tok_lbrace) { error(err_explbr, &t.pos); } else { int braces = 1; while (braces > 0) { dtor(t), t = get_token(in); if (t.type == tok_lbrace) braces++; else if (t.type == tok_rbrace) braces--; else if (t.type == tok_eof) { error(err_commenteof, &t.pos); break; } } } if (seenwhite) { already = TRUE; dtor(t), t = get_token(in); if (t.type == tok_white) { iswhite = TRUE; already = FALSE; } } break; case c_q: dtor(t), t = get_token(in); if (t.type != tok_lbrace) { error(err_explbr, &t.pos); } else { wd.text = NULL; wd.type = toquotestyle(style); wd.alt = NULL; wd.aux = quote_Open; wd.fpos = t.pos; wd.breaks = FALSE; if (!indexing || index_visible) addword(wd, &whptr); if (indexing) { rdadd(&indexstr, L'"'); addword(wd, &idximplicit); } sitem = mknew(struct stack_item); sitem->type = stack_quote; stk_push(parsestk, sitem); } break; case c_K: case c_k: case c_R: case c_W: case c_L: case c_date: /* * Keyword, hyperlink, or \date. We expect a * left brace, some text, and then a right * brace. No nesting; no arguments. */ wd.fpos = t.pos; wd.breaks = FALSE; if (t.cmd == c_K) wd.type = word_UpperXref; else if (t.cmd == c_k) wd.type = word_LowerXref; else if (t.cmd == c_R) wd.type = word_FreeTextXref; else if (t.cmd == c_W) wd.type = word_HyperLink; else if (t.cmd == c_L) wd.type = word_LocalHyperLink; else wd.type = word_Normal; dtor(t), t = get_token(in); if (t.type != tok_lbrace) { if (wd.type == word_Normal) { time_t thetime = time(NULL); struct tm *broken = localtime(&thetime); already = TRUE; wdtext = ustrftime(NULL, broken); wd.type = style; } else { error(err_explbr, &t.pos); wdtext = NULL; } } else { rdstring rs = { 0, 0, NULL }; while (dtor(t), t = get_token(in), t.type == tok_word || t.type == tok_white) { if (t.type == tok_white) rdadd(&rs, ' '); else rdadds(&rs, t.text); } if (wd.type == word_Normal) { time_t thetime = time(NULL); struct tm *broken = localtime(&thetime); wdtext = ustrftime(rs.text, broken); wd.type = style; } else { wdtext = ustrdup(rs.text); } sfree(rs.text); if (t.type != tok_rbrace) { error(err_kwexprbr, &t.pos); } } wd.alt = NULL; wd.aux = 0; if (!indexing || index_visible) { wd.text = ustrdup(wdtext); addword(wd, &whptr); } if (indexing) { wd.text = ustrdup(wdtext); addword(wd, &idximplicit); } sfree(wdtext); if (wd.type == word_FreeTextXref || wd.type == word_HyperLink || wd.type == word_LocalHyperLink) { /* * Hyperlinks are different: they then * expect another left brace, to begin * delimiting the text marked by the link. */ dtor(t), t = get_token(in); /* * Special cases: \W{}\c, \W{}\e, \W{}\cw */ sitem = mknew(struct stack_item); sitem->type = stack_hyper; if (t.type == tok_cmd && (t.cmd == c_e || t.cmd == c_c || t.cmd == c_cw)) { if (style != word_Normal) error(err_nestedstyles, &t.pos); else { style = (t.cmd == c_c ? word_Code : t.cmd == c_cw ? word_WeakCode : word_Emph); spcstyle = tospacestyle(style); sitem->type |= stack_style; } dtor(t), t = get_token(in); } if (t.type != tok_lbrace) { error(err_explbr, &t.pos); sfree(sitem); } else { stk_push(parsestk, sitem); } } break; case c_c: case c_cw: case c_e: type = t.cmd; if (style != word_Normal) { error(err_nestedstyles, &t.pos); /* Error recovery: eat lbrace, push nop. */ dtor(t), t = get_token(in); sitem = mknew(struct stack_item); sitem->type = stack_nop; stk_push(parsestk, sitem); } dtor(t), t = get_token(in); if (t.type != tok_lbrace) { error(err_explbr, &t.pos); } else { style = (type == c_c ? word_Code : type == c_cw ? word_WeakCode : word_Emph); spcstyle = tospacestyle(style); sitem = mknew(struct stack_item); sitem->type = stack_style; stk_push(parsestk, sitem); } break; case c_i: case c_ii: case c_I: type = t.cmd; if (indexing) { error(err_nestedindex, &t.pos); /* Error recovery: eat lbrace, push nop. */ dtor(t), t = get_token(in); sitem = mknew(struct stack_item); sitem->type = stack_nop; stk_push(parsestk, sitem); } sitem = mknew(struct stack_item); sitem->type = stack_idx; dtor(t), t = get_token(in); /* * Special cases: \i\c, \i\e, \i\cw */ wd.fpos = t.pos; if (t.type == tok_cmd && (t.cmd == c_e || t.cmd == c_c || t.cmd == c_cw)) { if (style != word_Normal) error(err_nestedstyles, &t.pos); else { style = (t.cmd == c_c ? word_Code : t.cmd == c_cw ? word_WeakCode : word_Emph); spcstyle = tospacestyle(style); sitem->type |= stack_style; } dtor(t), t = get_token(in); } if (t.type != tok_lbrace) { sfree(sitem); error(err_explbr, &t.pos); } else { /* Add an index-reference word with no text as yet */ wd.type = word_IndexRef; wd.text = NULL; wd.alt = NULL; wd.aux = 0; wd.breaks = FALSE; indexword = addword(wd, &whptr); /* Set up a rdstring to read the index text */ indexstr = nullrs; /* Flags so that we do the Right Things with text */ index_visible = (type != c_I); index_downcase = (type == c_ii); indexing = TRUE; idxwordlist = NULL; idximplicit = &idxwordlist; /* Stack item to close the indexing on exit */ stk_push(parsestk, sitem); } break; case c_u: uchr = t.aux; utext[0] = uchr; utext[1] = 0; wd.type = style; wd.breaks = FALSE; wd.alt = NULL; wd.aux = 0; wd.fpos = t.pos; if (!indexing || index_visible) { wd.text = ustrdup(utext); uword = addword(wd, &whptr); } else uword = NULL; if (indexing) { wd.text = ustrdup(utext); iword = addword(wd, &idximplicit); } else iword = NULL; dtor(t), t = get_token(in); if (t.type == tok_lbrace) { /* * \u with a left brace. Until the brace * closes, all further words go on a * sidetrack from the main thread of the * paragraph. */ sitem = mknew(struct stack_item); sitem->type = stack_ualt; sitem->whptr = whptr; sitem->idximplicit = idximplicit; stk_push(parsestk, sitem); whptr = uword ? &uword->alt : NULL; idximplicit = iword ? &iword->alt : NULL; } else { if (indexing) rdadd(&indexstr, uchr); already = TRUE; } break; default: if (!macrolookup(macros, in, t.text, &t.pos)) error(err_badmidcmd, t.text, &t.pos); break; }
char *winsock_error_string(int error) { const char prefix[] = "Network error: "; struct errstring *es; /* * Error codes we know about and have historically had reasonably * sensible error messages for. */ switch (error) { case WSAEACCES: return "Network error: Permission denied"; case WSAEADDRINUSE: return "Network error: Address already in use"; case WSAEADDRNOTAVAIL: return "Network error: Cannot assign requested address"; case WSAEAFNOSUPPORT: return "Network error: Address family not supported by protocol family"; case WSAEALREADY: return "Network error: Operation already in progress"; case WSAECONNABORTED: return "Network error: Software caused connection abort"; case WSAECONNREFUSED: return "Network error: Connection refused"; case WSAECONNRESET: return "Network error: Connection reset by peer"; case WSAEDESTADDRREQ: return "Network error: Destination address required"; case WSAEFAULT: return "Network error: Bad address"; case WSAEHOSTDOWN: return "Network error: Host is down"; case WSAEHOSTUNREACH: return "Network error: No route to host"; case WSAEINPROGRESS: return "Network error: Operation now in progress"; case WSAEINTR: return "Network error: Interrupted function call"; case WSAEINVAL: return "Network error: Invalid argument"; case WSAEISCONN: return "Network error: Socket is already connected"; case WSAEMFILE: return "Network error: Too many open files"; case WSAEMSGSIZE: return "Network error: Message too long"; case WSAENETDOWN: return "Network error: Network is down"; case WSAENETRESET: return "Network error: Network dropped connection on reset"; case WSAENETUNREACH: return "Network error: Network is unreachable"; case WSAENOBUFS: return "Network error: No buffer space available"; case WSAENOPROTOOPT: return "Network error: Bad protocol option"; case WSAENOTCONN: return "Network error: Socket is not connected"; case WSAENOTSOCK: return "Network error: Socket operation on non-socket"; case WSAEOPNOTSUPP: return "Network error: Operation not supported"; case WSAEPFNOSUPPORT: return "Network error: Protocol family not supported"; case WSAEPROCLIM: return "Network error: Too many processes"; case WSAEPROTONOSUPPORT: return "Network error: Protocol not supported"; case WSAEPROTOTYPE: return "Network error: Protocol wrong type for socket"; case WSAESHUTDOWN: return "Network error: Cannot send after socket shutdown"; case WSAESOCKTNOSUPPORT: return "Network error: Socket type not supported"; case WSAETIMEDOUT: return "Network error: Connection timed out"; case WSAEWOULDBLOCK: return "Network error: Resource temporarily unavailable"; case WSAEDISCON: return "Network error: Graceful shutdown in progress"; } /* * Generic code to handle any other error. * * Slightly nasty hack here: we want to return a static string * which the caller will never have to worry about freeing, but on * the other hand if we call FormatMessage to get it then it will * want to either allocate a buffer or write into one we own. * * So what we do is to maintain a tree234 of error strings we've * already used. New ones are allocated from the heap, but then * put in this tree and kept forever. */ if (!errstrings) errstrings = newtree234(errstring_compare); es = find234(errstrings, &error, errstring_find); if (!es) { int bufsize, bufused; es = snew(struct errstring); es->error = error; /* maximum size for FormatMessage is 64K */ bufsize = 65535 + sizeof(prefix); es->text = snewn(bufsize, char); strcpy(es->text, prefix); bufused = strlen(es->text); if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), es->text + bufused, bufsize - bufused, NULL)) { sprintf(es->text + bufused, "Windows error code %d (and FormatMessage returned %d)", error, GetLastError()); } else { int len = strlen(es->text); if (len > 0 && es->text[len-1] == '\n') es->text[len-1] = '\0'; } es->text = sresize(es->text, strlen(es->text) + 1, char); add234(errstrings, es); }
Socket platform_new_connection(SockAddr addr, const char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, Conf *conf) { char *cmd; static const struct socket_function_table socket_fn_table = { sk_localproxy_plug, sk_localproxy_close, sk_localproxy_write, sk_localproxy_write_oob, sk_localproxy_write_eof, sk_localproxy_flush, sk_localproxy_set_frozen, sk_localproxy_socket_error, NULL, /* peer_info */ }; Local_Proxy_Socket ret; int to_cmd_pipe[2], from_cmd_pipe[2], cmd_err_pipe[2], pid, proxytype; proxytype = conf_get_int(conf, CONF_proxy_type); if (proxytype != PROXY_CMD && proxytype != PROXY_FUZZ) return NULL; ret = snew(struct Socket_localproxy_tag); ret->fn = &socket_fn_table; ret->plug = plug; ret->error = NULL; ret->outgoingeof = EOF_NO; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); bufchain_init(&ret->pending_error_data); if (proxytype == PROXY_CMD) { cmd = format_telnet_command(addr, port, conf); if (flags & FLAG_STDERR) { /* If we have a sensible stderr, the proxy command can * send its own standard error there, so we won't * interfere. */ cmd_err_pipe[0] = cmd_err_pipe[1] = -1; } else { /* If we don't have a sensible stderr, we should catch the * proxy command's standard error to put in our event * log. */ cmd_err_pipe[0] = cmd_err_pipe[1] = 0; } { char *logmsg = dupprintf("Starting local proxy command: %s", cmd); plug_log(plug, 2, NULL, 0, logmsg, 0); sfree(logmsg); } /* * Create the pipes to the proxy command, and spawn the proxy * command process. */ if (pipe(to_cmd_pipe) < 0 || pipe(from_cmd_pipe) < 0 || (cmd_err_pipe[0] == 0 && pipe(cmd_err_pipe) < 0)) { ret->error = dupprintf("pipe: %s", strerror(errno)); sfree(cmd); return (Socket)ret; } cloexec(to_cmd_pipe[1]); cloexec(from_cmd_pipe[0]); if (cmd_err_pipe[0] >= 0) cloexec(cmd_err_pipe[0]); pid = fork(); if (pid < 0) { ret->error = dupprintf("fork: %s", strerror(errno)); sfree(cmd); return (Socket)ret; } else if (pid == 0) { close(0); close(1); dup2(to_cmd_pipe[0], 0); dup2(from_cmd_pipe[1], 1); close(to_cmd_pipe[0]); close(from_cmd_pipe[1]); if (cmd_err_pipe[0] >= 0) { dup2(cmd_err_pipe[1], 2); close(cmd_err_pipe[1]); } noncloexec(0); noncloexec(1); execl("/bin/sh", "sh", "-c", cmd, (void *)NULL); _exit(255); } sfree(cmd); close(to_cmd_pipe[0]); close(from_cmd_pipe[1]); if (cmd_err_pipe[0] >= 0) close(cmd_err_pipe[1]); ret->to_cmd = to_cmd_pipe[1]; ret->from_cmd = from_cmd_pipe[0]; ret->cmd_err = cmd_err_pipe[0]; } else { cmd = format_telnet_command(addr, port, conf); ret->to_cmd = open("/dev/null", O_WRONLY); if (ret->to_cmd == -1) { ret->error = dupprintf("/dev/null: %s", strerror(errno)); sfree(cmd); return (Socket)ret; } ret->from_cmd = open(cmd, O_RDONLY); if (ret->from_cmd == -1) { ret->error = dupprintf("%s: %s", cmd, strerror(errno)); sfree(cmd); return (Socket)ret; } sfree(cmd); ret->cmd_err = -1; } if (!localproxy_by_fromfd) localproxy_by_fromfd = newtree234(localproxy_fromfd_cmp); if (!localproxy_by_tofd) localproxy_by_tofd = newtree234(localproxy_tofd_cmp); if (!localproxy_by_errfd) localproxy_by_errfd = newtree234(localproxy_errfd_cmp); add234(localproxy_by_fromfd, ret); add234(localproxy_by_tofd, ret); if (ret->cmd_err >= 0) add234(localproxy_by_errfd, ret); uxsel_set(ret->from_cmd, 1, localproxy_select_result); if (ret->cmd_err >= 0) uxsel_set(ret->cmd_err, 1, localproxy_select_result); /* We are responsible for this and don't need it any more */ sk_addr_free(addr); return (Socket) ret; }
void sk_init(void) { #ifndef NO_IPV6 winsock2_module = #endif winsock_module = load_system32_dll("ws2_32.dll"); if (!winsock_module) { winsock_module = load_system32_dll("wsock32.dll"); } if (!winsock_module) fatalbox("Unable to load any WinSock library"); #ifndef NO_IPV6 /* Check if we have getaddrinfo in Winsock */ if (GetProcAddress(winsock_module, "getaddrinfo") != NULL) { #ifdef NET_SETUP_DIAGNOSTICS logevent(NULL, "Native WinSock IPv6 support detected"); #endif GET_WINDOWS_FUNCTION(winsock_module, getaddrinfo); GET_WINDOWS_FUNCTION(winsock_module, freeaddrinfo); GET_WINDOWS_FUNCTION(winsock_module, getnameinfo); GET_WINDOWS_FUNCTION(winsock_module, gai_strerror); } else { /* Fall back to wship6.dll for Windows 2000 */ wship6_module = load_system32_dll("wship6.dll"); if (wship6_module) { #ifdef NET_SETUP_DIAGNOSTICS logevent(NULL, "WSH IPv6 support detected"); #endif GET_WINDOWS_FUNCTION(wship6_module, getaddrinfo); GET_WINDOWS_FUNCTION(wship6_module, freeaddrinfo); GET_WINDOWS_FUNCTION(wship6_module, getnameinfo); GET_WINDOWS_FUNCTION(wship6_module, gai_strerror); } else { #ifdef NET_SETUP_DIAGNOSTICS logevent(NULL, "No IPv6 support detected"); #endif } } GET_WINDOWS_FUNCTION(winsock2_module, WSAAddressToStringA); #else #ifdef NET_SETUP_DIAGNOSTICS logevent(NULL, "PuTTY was built without IPv6 support"); #endif #endif GET_WINDOWS_FUNCTION(winsock_module, WSAAsyncSelect); GET_WINDOWS_FUNCTION(winsock_module, WSAEventSelect); GET_WINDOWS_FUNCTION(winsock_module, select); GET_WINDOWS_FUNCTION(winsock_module, WSAGetLastError); GET_WINDOWS_FUNCTION(winsock_module, WSAEnumNetworkEvents); GET_WINDOWS_FUNCTION(winsock_module, WSAStartup); GET_WINDOWS_FUNCTION(winsock_module, WSACleanup); GET_WINDOWS_FUNCTION(winsock_module, closesocket); GET_WINDOWS_FUNCTION(winsock_module, ntohl); GET_WINDOWS_FUNCTION(winsock_module, htonl); GET_WINDOWS_FUNCTION(winsock_module, htons); GET_WINDOWS_FUNCTION(winsock_module, ntohs); GET_WINDOWS_FUNCTION(winsock_module, gethostname); GET_WINDOWS_FUNCTION(winsock_module, gethostbyname); GET_WINDOWS_FUNCTION(winsock_module, getservbyname); GET_WINDOWS_FUNCTION(winsock_module, inet_addr); GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa); GET_WINDOWS_FUNCTION(winsock_module, inet_ntop); GET_WINDOWS_FUNCTION(winsock_module, connect); GET_WINDOWS_FUNCTION(winsock_module, bind); GET_WINDOWS_FUNCTION(winsock_module, setsockopt); GET_WINDOWS_FUNCTION(winsock_module, socket); GET_WINDOWS_FUNCTION(winsock_module, listen); GET_WINDOWS_FUNCTION(winsock_module, send); GET_WINDOWS_FUNCTION(winsock_module, shutdown); GET_WINDOWS_FUNCTION(winsock_module, ioctlsocket); GET_WINDOWS_FUNCTION(winsock_module, accept); GET_WINDOWS_FUNCTION(winsock_module, getpeername); GET_WINDOWS_FUNCTION(winsock_module, recv); GET_WINDOWS_FUNCTION(winsock_module, WSAIoctl); /* Try to get the best WinSock version we can get */ if (!sk_startup(2,2) && !sk_startup(2,0) && !sk_startup(1,1)) { fatalbox("Unable to initialise WinSock"); } sktree = newtree234(cmpfortree); }
int main(void) { int in[NSTR]; int i, j, k; unsigned seed = 0; for (i = 0; i < NSTR; i++) in[i] = 0; array = NULL; arraylen = arraysize = 0; tree = newtree234(mycmp); cmp = mycmp; verify(); for (i = 0; i < 10000; i++) { j = randomnumber(&seed); j %= NSTR; printf("trial: %d\n", i); if (in[j]) { printf("deleting %s (%d)\n", strings[j], j); deltest(strings[j]); in[j] = 0; } else { printf("adding %s (%d)\n", strings[j], j); addtest(strings[j]); in[j] = 1; } findtest(); } while (arraylen > 0) { j = randomnumber(&seed); j %= arraylen; deltest(array[j]); } freetree234(tree); /* * Now try an unsorted tree. We don't really need to test * delpos234 because we know del234 is based on it, so it's * already been tested in the above sorted-tree code; but for * completeness we'll use it to tear down our unsorted tree * once we've built it. */ tree = newtree234(NULL); cmp = NULL; verify(); for (i = 0; i < 1000; i++) { printf("trial: %d\n", i); j = randomnumber(&seed); j %= NSTR; k = randomnumber(&seed); k %= count234(tree)+1; printf("adding string %s at index %d\n", strings[j], k); addpostest(strings[j], k); } while (count234(tree) > 0) { printf("cleanup: tree size %d\n", count234(tree)); j = randomnumber(&seed); j %= count234(tree); printf("deleting string %s from index %d\n", array[j], j); delpostest(j); } return 0; }
void sk_init(void) { #ifndef NO_IPV6 winsock2_module = #endif winsock_module = load_system32_dll("ws2_32.dll"); if (!winsock_module) { winsock_module = load_system32_dll("wsock32.dll"); } if (!winsock_module) modalfatalbox("Unable to load any WinSock library"); #ifndef NO_IPV6 /* Check if we have getaddrinfo in Winsock */ if (GetProcAddress(winsock_module, "getaddrinfo") != NULL) { GET_WINDOWS_FUNCTION(winsock_module, getaddrinfo); GET_WINDOWS_FUNCTION(winsock_module, freeaddrinfo); GET_WINDOWS_FUNCTION(winsock_module, getnameinfo); /* This function would fail its type-check if we did one, * because the VS header file provides an inline definition * which is __cdecl instead of WINAPI. */ GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror); } else { /* Fall back to wship6.dll for Windows 2000 */ wship6_module = load_system32_dll("wship6.dll"); if (wship6_module) { GET_WINDOWS_FUNCTION(wship6_module, getaddrinfo); GET_WINDOWS_FUNCTION(wship6_module, freeaddrinfo); GET_WINDOWS_FUNCTION(wship6_module, getnameinfo); /* See comment above about type check */ GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gai_strerror); } else { } } GET_WINDOWS_FUNCTION(winsock2_module, WSAAddressToStringA); #endif GET_WINDOWS_FUNCTION(winsock_module, WSAAsyncSelect); GET_WINDOWS_FUNCTION(winsock_module, WSAEventSelect); /* We don't type-check select because at least some MinGW versions * of the Windows API headers seem to disagree with the * documentation on whether the 'struct timeval *' pointer is * const or not. */ GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, select); GET_WINDOWS_FUNCTION(winsock_module, WSAGetLastError); GET_WINDOWS_FUNCTION(winsock_module, WSAEnumNetworkEvents); GET_WINDOWS_FUNCTION(winsock_module, WSAStartup); GET_WINDOWS_FUNCTION(winsock_module, WSACleanup); GET_WINDOWS_FUNCTION(winsock_module, closesocket); #ifndef COVERITY GET_WINDOWS_FUNCTION(winsock_module, ntohl); GET_WINDOWS_FUNCTION(winsock_module, htonl); GET_WINDOWS_FUNCTION(winsock_module, htons); GET_WINDOWS_FUNCTION(winsock_module, ntohs); GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gethostname); #else /* The toolchain I use for Windows Coverity builds doesn't know * the type signatures of these */ GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, ntohl); GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, htonl); GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, htons); GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, ntohs); GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, gethostname); #endif GET_WINDOWS_FUNCTION(winsock_module, gethostbyname); GET_WINDOWS_FUNCTION(winsock_module, getservbyname); GET_WINDOWS_FUNCTION(winsock_module, inet_addr); GET_WINDOWS_FUNCTION(winsock_module, inet_ntoa); #if (defined _MSC_VER && _MSC_VER < 1900) || defined __MINGW32__ /* Older Visual Studio, and MinGW as of Ubuntu 16.04, don't know * about this function at all, so can't type-check it */ GET_WINDOWS_FUNCTION_NO_TYPECHECK(winsock_module, inet_ntop); #else GET_WINDOWS_FUNCTION(winsock_module, inet_ntop); #endif GET_WINDOWS_FUNCTION(winsock_module, connect); GET_WINDOWS_FUNCTION(winsock_module, bind); GET_WINDOWS_FUNCTION(winsock_module, setsockopt); GET_WINDOWS_FUNCTION(winsock_module, socket); GET_WINDOWS_FUNCTION(winsock_module, listen); GET_WINDOWS_FUNCTION(winsock_module, send); GET_WINDOWS_FUNCTION(winsock_module, shutdown); GET_WINDOWS_FUNCTION(winsock_module, ioctlsocket); GET_WINDOWS_FUNCTION(winsock_module, accept); GET_WINDOWS_FUNCTION(winsock_module, getpeername); GET_WINDOWS_FUNCTION(winsock_module, recv); GET_WINDOWS_FUNCTION(winsock_module, WSAIoctl); /* Try to get the best WinSock version we can get */ if (!sk_startup(2,2) && !sk_startup(2,0) && !sk_startup(1,1)) { modalfatalbox("Unable to initialise WinSock"); } sktree = newtree234(cmpfortree); }
static void pty_open_master(Pty pty) { #ifdef BSD_PTYS const char chars1[] = "pqrstuvwxyz"; const char chars2[] = "0123456789abcdef"; const char *p1, *p2; char master_name[20]; struct group *gp; for (p1 = chars1; *p1; p1++) for (p2 = chars2; *p2; p2++) { sprintf(master_name, "/dev/pty%c%c", *p1, *p2); pty->master_fd = open(master_name, O_RDWR); if (pty->master_fd >= 0) { if (geteuid() == 0 || access(master_name, R_OK | W_OK) == 0) { /* * We must also check at this point that we are * able to open the slave side of the pty. We * wouldn't want to allocate the wrong master, * get all the way down to forking, and _then_ * find we're unable to open the slave. */ strcpy(pty->name, master_name); pty->name[5] = 't'; /* /dev/ptyXX -> /dev/ttyXX */ cloexec(pty->master_fd); if (pty_open_slave(pty) >= 0 && access(pty->name, R_OK | W_OK) == 0) goto got_one; if (pty->slave_fd > 0) close(pty->slave_fd); pty->slave_fd = -1; } close(pty->master_fd); } } /* If we get here, we couldn't get a tty at all. */ fprintf(stderr, "pterm: unable to open a pseudo-terminal device\n"); exit(1); got_one: /* We need to chown/chmod the /dev/ttyXX device. */ gp = getgrnam("tty"); chown(pty->name, getuid(), gp ? gp->gr_gid : -1); chmod(pty->name, 0600); #else const int flags = O_RDWR #ifdef O_NOCTTY | O_NOCTTY #endif ; #ifdef HAVE_POSIX_OPENPT #ifdef SET_NONBLOCK_VIA_OPENPT /* * OS X, as of 10.10 at least, doesn't permit me to set O_NONBLOCK * on pty master fds via the usual fcntl mechanism. Fortunately, * it does let me work around this by adding O_NONBLOCK to the * posix_openpt flags parameter, which isn't a documented use of * the API but seems to work. So we'll do that for now. */ pty->master_fd = posix_openpt(flags | O_NONBLOCK); #else pty->master_fd = posix_openpt(flags); #endif if (pty->master_fd < 0) { perror("posix_openpt"); exit(1); } #else pty->master_fd = open("/dev/ptmx", flags); if (pty->master_fd < 0) { perror("/dev/ptmx: open"); exit(1); } #endif if (grantpt(pty->master_fd) < 0) { perror("grantpt"); exit(1); } if (unlockpt(pty->master_fd) < 0) { perror("unlockpt"); exit(1); } cloexec(pty->master_fd); pty->name[FILENAME_MAX-1] = '\0'; strncpy(pty->name, ptsname(pty->master_fd), FILENAME_MAX-1); #endif #ifndef SET_NONBLOCK_VIA_OPENPT nonblock(pty->master_fd); #endif if (!ptys_by_fd) ptys_by_fd = newtree234(pty_compare_by_fd); add234(ptys_by_fd, pty); }
Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, Plug plug, Conf *conf) { char *cmd; static const struct socket_function_table socket_fn_table = { sk_localproxy_plug, sk_localproxy_close, sk_localproxy_write, sk_localproxy_write_oob, sk_localproxy_write_eof, sk_localproxy_flush, sk_localproxy_set_frozen, sk_localproxy_socket_error, NULL, /* peer_info */ }; Local_Proxy_Socket ret; int to_cmd_pipe[2], from_cmd_pipe[2], pid; if (conf_get_int(conf, CONF_proxy_type) != PROXY_CMD) return NULL; cmd = format_telnet_command(addr, port, conf); ret = snew(struct Socket_localproxy_tag); ret->fn = &socket_fn_table; ret->plug = plug; ret->error = NULL; ret->outgoingeof = EOF_NO; bufchain_init(&ret->pending_input_data); bufchain_init(&ret->pending_output_data); /* * Create the pipes to the proxy command, and spawn the proxy * command process. */ if (pipe(to_cmd_pipe) < 0 || pipe(from_cmd_pipe) < 0) { ret->error = dupprintf("pipe: %s", strerror(errno)); sfree(cmd); return (Socket)ret; } cloexec(to_cmd_pipe[1]); cloexec(from_cmd_pipe[0]); pid = fork(); if (pid < 0) { ret->error = dupprintf("fork: %s", strerror(errno)); sfree(cmd); return (Socket)ret; } else if (pid == 0) { close(0); close(1); dup2(to_cmd_pipe[0], 0); dup2(from_cmd_pipe[1], 1); close(to_cmd_pipe[0]); close(from_cmd_pipe[1]); noncloexec(0); noncloexec(1); execl("/bin/sh", "sh", "-c", cmd, (void *)NULL); _exit(255); } sfree(cmd); close(to_cmd_pipe[0]); close(from_cmd_pipe[1]); ret->to_cmd = to_cmd_pipe[1]; ret->from_cmd = from_cmd_pipe[0]; if (!localproxy_by_fromfd) localproxy_by_fromfd = newtree234(localproxy_fromfd_cmp); if (!localproxy_by_tofd) localproxy_by_tofd = newtree234(localproxy_tofd_cmp); add234(localproxy_by_fromfd, ret); add234(localproxy_by_tofd, ret); uxsel_set(ret->from_cmd, 1, localproxy_select_result); /* We are responsible for this and don't need it any more */ sk_addr_free(addr); return (Socket) ret; }