Exemple #1
0
/*
 * 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);
Exemple #2
0
indexdata *make_index(void) {
    indexdata *ret = snew(indexdata);
    ret->tags = newtree234(compare_tags);
    ret->entries = newtree234(compare_entries);
    return ret;
}
Exemple #3
0
void sk_init(void)
{
    sktree = newtree234(cmpfortree);
}
Exemple #4
0
/*
 * 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(&macrotext, L'\n');
            rdadds(&macrotext, 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;
        }
Exemple #5
0
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);
    }
Exemple #6
0
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;
}
Exemple #7
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)
	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);
}
Exemple #8
0
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;
}
Exemple #9
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);
}
Exemple #10
0
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);
}
Exemple #11
0
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;
}