From 877b3d84597fcfc3abf5aa332019d412f2717896 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Wed, 20 Apr 2011 23:24:51 +0100 Subject: Rename the remaining poky-* scripts to oe-* or runqemu-* Signed-off-by: Richard Purdie --- scripts/oe-find-native-sysroot | 72 + scripts/oe-git-proxy-command | 10 + scripts/oe-git-proxy-socks-command | 2 + scripts/oe-git-proxy-socks.c | 2982 ++++++++++++++++++++++++++++++++++ scripts/oe-setup-rpmrepo | 89 + scripts/oe-trim-schemas | 49 + scripts/poky-addptable2image | 51 - scripts/poky-export-rootfs | 186 --- scripts/poky-extract-sdk | 100 -- scripts/poky-find-native-sysroot | 72 - scripts/poky-gen-tapdevs | 85 - scripts/poky-git-proxy-command | 10 - scripts/poky-git-proxy-socks-command | 2 - scripts/poky-git-proxy-socks.c | 2982 ---------------------------------- scripts/poky-setup-rpmrepo | 89 - scripts/poky-trim-schemas | 49 - scripts/runqemu-addptable2image | 51 + scripts/runqemu-export-rootfs | 186 +++ scripts/runqemu-extract-sdk | 100 ++ scripts/runqemu-gen-tapdevs | 85 + scripts/runqemu-ifup | 2 +- scripts/runqemu-internal | 12 +- 22 files changed, 3633 insertions(+), 3633 deletions(-) create mode 100755 scripts/oe-find-native-sysroot create mode 100755 scripts/oe-git-proxy-command create mode 100755 scripts/oe-git-proxy-socks-command create mode 100644 scripts/oe-git-proxy-socks.c create mode 100755 scripts/oe-setup-rpmrepo create mode 100755 scripts/oe-trim-schemas delete mode 100755 scripts/poky-addptable2image delete mode 100755 scripts/poky-export-rootfs delete mode 100755 scripts/poky-extract-sdk delete mode 100755 scripts/poky-find-native-sysroot delete mode 100755 scripts/poky-gen-tapdevs delete mode 100755 scripts/poky-git-proxy-command delete mode 100755 scripts/poky-git-proxy-socks-command delete mode 100644 scripts/poky-git-proxy-socks.c delete mode 100755 scripts/poky-setup-rpmrepo delete mode 100755 scripts/poky-trim-schemas create mode 100755 scripts/runqemu-addptable2image create mode 100755 scripts/runqemu-export-rootfs create mode 100755 scripts/runqemu-extract-sdk create mode 100755 scripts/runqemu-gen-tapdevs (limited to 'scripts') diff --git a/scripts/oe-find-native-sysroot b/scripts/oe-find-native-sysroot new file mode 100755 index 0000000000..da00a07850 --- /dev/null +++ b/scripts/oe-find-native-sysroot @@ -0,0 +1,72 @@ +#!/bin/bash +# +# Find a native sysroot to use - either from an in-tree Poky build or +# from a toolchain installation. It then ensures the variable +# $OECORE_NATIVE_SYSROOT is set to the sysroot's base directory, and sets +# $PSEUDO to the path of the pseudo binary. +# +# This script is intended to be run within other scripts by source'ing +# it, e.g: +# +# SYSROOT_SETUP_SCRIPT=`which oe-find-native-sysroot` +# . $SYSROOT_SETUP_SCRIPT +# +# This script will terminate execution of your calling program unless +# you set a variable $SKIP_STRICT_SYSROOT_CHECK to a non-empty string +# beforehand. +# +# Copyright (c) 2010 Intel Corp. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +if [ -z "$OECORE_NATIVE_SYSROOT" ]; then + BITBAKE=`which bitbake` + if [ "x$BITBAKE" != "x" ]; then + if [ "$UID" = "0" ]; then + # Root cannot run bitbake unless sanity checking is disabled + if [ ! -d "./conf" ]; then + echo "Error: root cannot run bitbake by default, and I cannot find a ./conf directory to be able to disable sanity checking" + exit 1 + fi + touch conf/sanity.conf + OECORE_NATIVE_SYSROOT=`bitbake -e | grep ^STAGING_DIR_NATIVE | cut -d '=' -f2 | cut -d '"' -f2` + rm -f conf/sanity.conf + else + OECORE_NATIVE_SYSROOT=`bitbake -e | grep ^STAGING_DIR_NATIVE | cut -d '=' -f2 | cut -d '"' -f2` + fi + else + echo "Error: Unable to locate your native sysroot." + echo "Did you forget to source the Poky environment script?" + + if [ -z "$SKIP_STRICT_SYSROOT_CHECK" ]; then + exit 1 + fi + fi +fi + +# Set up pseudo command +if [ ! -e "$OECORE_NATIVE_SYSROOT/usr/bin/pseudo" ]; then + echo "Error: Unable to find pseudo binary in $OECORE_NATIVE_SYSROOT/usr/bin/" + + if [ "x$POKY_DISTRO_VERSION" = "x" ]; then + echo "Have you run 'bitbake meta-ide-support'?" + else + echo "This shouldn't happen - something is wrong with your toolchain installation" + fi + + if [ -z "$SKIP_STRICT_SYSROOT_CHECK" ]; then + exit 1 + fi +fi +PSEUDO="$OECORE_NATIVE_SYSROOT/usr/bin/pseudo" diff --git a/scripts/oe-git-proxy-command b/scripts/oe-git-proxy-command new file mode 100755 index 0000000000..d31f85abd8 --- /dev/null +++ b/scripts/oe-git-proxy-command @@ -0,0 +1,10 @@ +#! /bin/bash + +(echo "CONNECT $1:$2 HTTP/1.0"; + echo; + cat ) | nc $GIT_PROXY_HOST $GIT_PROXY_PORT | + +(read a; + read a; + read a; + cat ) \ No newline at end of file diff --git a/scripts/oe-git-proxy-socks-command b/scripts/oe-git-proxy-socks-command new file mode 100755 index 0000000000..90fa14e1ed --- /dev/null +++ b/scripts/oe-git-proxy-socks-command @@ -0,0 +1,2 @@ +#! /bin/bash +oe-git-proxy-socks -S $GIT_PROXY_HOST:$GIT_PROXY_PORT $@ diff --git a/scripts/oe-git-proxy-socks.c b/scripts/oe-git-proxy-socks.c new file mode 100644 index 0000000000..f5747117ab --- /dev/null +++ b/scripts/oe-git-proxy-socks.c @@ -0,0 +1,2982 @@ +/*********************************************************************** + * connect.c -- Make socket connection using SOCKS4/5 and HTTP tunnel. + * + * Copyright (c) 2000-2006 Shun-ichi Goto + * Copyright (c) 2002, J. Grant (English Corrections) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * --------------------------------------------------------- + * PROJECT: My Test Program + * AUTHOR: Shun-ichi GOTO + * CREATE: Wed Jun 21, 2000 + * REVISION: $Revision: 100 $ + * --------------------------------------------------------- + * + * Getting Source + * ============== + * + * Recent version of 'connect.c' is available from + * http://www.taiyo.co.jp/~gotoh/ssh/connect.c + * + * Related tool, ssh-askpass.exe (alternative ssh-askpass on UNIX) + * is available: + * http://www.taiyo.co.jp/~gotoh/ssh/ssh-askpass.exe.gz + * + * See more detail: + * http://www.taiyo.co.jp/~gotoh/ssh/connect.html + * + * How To Compile + * ============== + * + * On UNIX environment: + * $ gcc connect.c -o connect + * + * On SOLARIS: + * $ gcc -o connect -lresolv -lsocket -lnsl connect.c + * + * on Win32 environment: + * $ cl connect.c wsock32.lib advapi32.lib + * or + * $ bcc32 connect.c wsock32.lib advapi32.lib + * or + * $ gcc connect.c -o connect + * + * on Mac OS X environment: + * $ gcc connect.c -o connect -lresolv + * or + * $ gcc connect.c -o connect -DBIND_8_COMPAT=1 + * + * How To Use + * ========== + * + * You can specify proxy method in an environment variable or in a + * command line option. + * + * usage: connect [-dnhst45] [-R resolve] [-p local-port] [-w sec] + * [-H [user@]proxy-server[:port]] + * [-S [user@]socks-server[:port]] + * [-T proxy-server[:port]] + * [-c telnet proxy command] + * host port + * + * "host" and "port" is for the target hostname and port-number to + * connect to. + * + * The -H option specifys a hostname and port number of the http proxy + * server to relay. If port is omitted, 80 is used. You can specify this + * value in the environment variable HTTP_PROXY and pass the -h option + * to use it. + * + * The -S option specifys the hostname and port number of the SOCKS + * server to relay. Like -H, port number can be omitted and the default + * is 1080. You can also specify this value pair in the environment + * variable SOCKS5_SERVER and give the -s option to use it. + * + * The '-4' and the '-5' options are for specifying SOCKS relaying and + * indicates protocol version to use. It is valid only when used with + * '-s' or '-S'. Default is '-5' (protocol version 5) + * + * The '-R' option is for specifying method to resolve the + * hostname. Three keywords ("local", "remote", "both") or dot-notation + * IP address are acceptable. The keyword "both" means, "Try local + * first, then remote". If a dot-notation IP address is specified, use + * this host as nameserver. The default is "remote" for SOCKS5 or + * "local" for others. On SOCKS4 protocol, remote resolving method + * ("remote" and "both") requires protocol 4a supported server. + * + * The '-p' option will forward a local TCP port instead of using the + * standard input and output. + * + * The '-P' option is same to '-p' except keep remote session. The + * program repeats waiting the port with holding remote session without + * disconnecting. To disconnect the remote session, send EOF to stdin or + * kill the program. + * + * The '-w' option specifys timeout seconds for making connection with + * TARGET host. + * + * The '-d' option is used for debug. If you fail to connect, use this + * and check request to and response from server. + * + * You can omit the "port" argument when program name is special format + * containing port number itself. For example, + * $ ln -s connect connect-25 + * means this connect-25 command is spcifying port number 25 already + * so you need not 2nd argument (and ignored if specified). + * + * To use proxy, this example is for SOCKS5 connection to connect to + * 'host' at port 25 via SOCKS5 server on 'firewall' host. + * $ connect -S firewall host 25 + * or + * $ SOCKS5_SERVER=firewall; export SOCKS5_SERVER + * $ connect -s host 25 + * + * For a HTTP-PROXY connection: + * $ connect -H proxy-server:8080 host 25 + * or + * $ HTTP_PROXY=proxy-server:8080; export HTTP_PROXY + * $ connect -h host 25 + * To forward a local port, for example to use ssh: + * $ connect -p 5550 -H proxy-server:8080 host 22 + * ($ ssh -l user -p 5550 localhost ) + * + * TIPS + * ==== + * + * Connect.c doesn't have any configuration to specify the SOCKS server. + * If you are a mobile user, this limitation might bother you. However, + * You can compile connect.c and link with other standard SOCKS library + * like the NEC SOCKS5 library or Dante. This means connect.c is + * socksified and uses a configration file like to other SOCKSified + * network commands and you can switch configuration file any time + * (ex. when ppp startup) that brings you switching of SOCKS server for + * connect.c in same way with other commands. For this case, you can + * write ~/.ssh/config like this: + * + * ProxyCommand connect -n %h %p + * + * SOCKS5 authentication + * ===================== + * + * Only USER/PASS authentication is supported. + * + * Proxy authentication + * ==================== + * + * Only BASIC scheme is supported. + * + * Authentication informations + * =========================== + * + * User name for authentication is specifed by an environment variable + * or system login name. And password is specified from environment + * variable or external program (specified in $SSH_ASKPASS) or tty. + * + * Following environment variable is used for specifying user name. + * SOCKS: $SOCKS5_USER, $LOGNAME, $USER + * HTTP Proxy: $HTTP_PROXY_USER, $LOGNAME, $USER + * + * ssh-askpass support + * =================== + * + * You can use ssh-askpass (came from OpenSSH or else) to specify + * password on graphical environment (X-Window or MS Windows). To use + * this, set program name to environment variable SSH_ASKPASS. On UNIX, + * X-Window must be required, so $DISPLAY environment variable is also + * needed. On Win32 environment, $DISPLAY is not mentioned. + * + * Related Informations + * ==================== + * + * SOCKS5 -- RFC 1928, RFC 1929, RFC 1961 + * NEC SOCKS Reference Implementation is available from: + * http://www.socks.nec.com + * DeleGate version 5 or earlier can be SOCKS4 server, + * and version 6 can be SOCKS5 and SOCKS4 server. + * and version 7.7.0 or later can be SOCKS5 and SOCKS4a server. + * http://www.delegate.org/delegate/ + * + * HTTP-Proxy -- + * Many http proxy servers supports this, but https should + * be allowed as configuration on your host. + * For example on DeleGate, you should add "https" to the + * "REMITTABLE" parameter to allow HTTP-Proxy like this: + * delegated -Pxxxx ...... REMITTABLE="+,https" ... + * + * Hypertext Transfer Protocol -- HTTP/1.1 -- RFC 2616 + * HTTP Authentication: Basic and Digest Access Authentication -- RFC 2617 + * For proxy authentication, refer these documents. + * + ***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __CYGWIN32__ +#undef _WIN32 +#endif + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#else /* !_WIN32 */ +#include +#include +#include +#include +#ifndef __hpux +#include +#endif /* __hpux */ +#include +#include +#include +#include +#if !defined(_WIN32) && !defined(__CYGWIN32__) +#define WITH_RESOLVER 1 +#include +#include +#else /* not ( not _WIN32 && not __CYGWIN32__) */ +#undef WITH_RESOLVER +#endif /* not ( not _WIN32 && not __CYGWIN32__) */ +#endif /* !_WIN32 */ + +#ifdef _WIN32 +#define ECONNRESET WSAECONNRESET +#endif /* _WI32 */ + + + +#ifndef LINT +static char *vcid = "$Id: connect.c 100 2007-07-03 10:48:26Z gotoh $"; +#endif + +/* Microsoft Visual C/C++ has _snprintf() and _vsnprintf() */ +#ifdef _MSC_VER +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif + +/* consider Borland C */ +#ifdef __BORLANDC__ +#define _kbhit kbhit +#define _setmode setmode +#endif + +/* help message. + Win32 environment does not support -R option (vc and cygwin) + Win32 native compilers does not support -w option, yet (vc) +*/ +static char *usage = "usage: %s [-dnhst45] [-p local-port]" +#ifdef _WIN32 +#ifdef __CYGWIN32__ +"[-w timeout] \n" /* cygwin cannot -R */ +#else /* not __CYGWIN32__ */ +" \n" /* VC cannot -w nor -R */ +#endif /* not __CYGWIN32__ */ +#else /* not _WIN32 */ +/* help message for UNIX */ +"[-R resolve] [-w timeout] \n" +#endif /* not _WIN32 */ +" [-H proxy-server[:port]] [-S [user@]socks-server[:port]] \n" +" [-T proxy-server[:port]]\n" +" [-c telnet-proxy-command]\n" +" host port\n"; + +/* name of this program */ +char *progname = NULL; +char *progdesc = "connect --- simple relaying command via proxy."; +char *rcs_revstr = "$Revision: 100 $"; +char *revstr = NULL; +int major_version = 1; +int minor_version = 0; + +/* set of character for strspn() */ +const char *digits = "0123456789"; +const char *dotdigits = "0123456789."; + +/* options */ +int f_debug = 0; + +/* report flag to hide secure information */ +int f_report = 1; + +int connect_timeout = 0; + +/* local input type */ +#define LOCAL_STDIO 0 +#define LOCAL_SOCKET 1 +char *local_type_names[] = { "stdio", "socket" }; +int local_type = LOCAL_STDIO; +u_short local_port = 0; /* option 'p' */ +int f_hold_session = 0; /* option 'P' */ + +char *telnet_command = "telnet %h %p"; + +/* utiity types, pair holder of number and string */ +typedef struct { + int num; + const char *str; +} LOOKUP_ITEM; + +/* relay method, server and port */ +#define METHOD_UNDECIDED 0 +#define METHOD_DIRECT 1 +#define METHOD_SOCKS 2 +#define METHOD_HTTP 3 +#define METHOD_TELNET 4 +char *method_names[] = { "UNDECIDED", "DIRECT", "SOCKS", "HTTP", "TELNET" }; + +int relay_method = METHOD_UNDECIDED; /* relaying method */ +char *relay_host = NULL; /* hostname of relay server */ +u_short relay_port = 0; /* port of relay server */ +char *relay_user = NULL; /* user name for auth */ + +/* destination target host and port */ +char *dest_host = NULL; +struct sockaddr_in dest_addr; +u_short dest_port = 0; + +/* informations for SOCKS */ +#define SOCKS5_REP_SUCCEEDED 0x00 /* succeeded */ +#define SOCKS5_REP_FAIL 0x01 /* general SOCKS serer failure */ +#define SOCKS5_REP_NALLOWED 0x02 /* connection not allowed by ruleset */ +#define SOCKS5_REP_NUNREACH 0x03 /* Network unreachable */ +#define SOCKS5_REP_HUNREACH 0x04 /* Host unreachable */ +#define SOCKS5_REP_REFUSED 0x05 /* connection refused */ +#define SOCKS5_REP_EXPIRED 0x06 /* TTL expired */ +#define SOCKS5_REP_CNOTSUP 0x07 /* Command not supported */ +#define SOCKS5_REP_ANOTSUP 0x08 /* Address not supported */ +#define SOCKS5_REP_INVADDR 0x09 /* Inalid address */ + +LOOKUP_ITEM socks5_rep_names[] = { + { SOCKS5_REP_SUCCEEDED, "succeeded"}, + { SOCKS5_REP_FAIL, "general SOCKS server failure"}, + { SOCKS5_REP_NALLOWED, "connection not allowed by ruleset"}, + { SOCKS5_REP_NUNREACH, "Network unreachable"}, + { SOCKS5_REP_HUNREACH, "Host unreachable"}, + { SOCKS5_REP_REFUSED, "connection refused"}, + { SOCKS5_REP_EXPIRED, "TTL expired"}, + { SOCKS5_REP_CNOTSUP, "Command not supported"}, + { SOCKS5_REP_ANOTSUP, "Address not supported"}, + { SOCKS5_REP_INVADDR, "Invalid address"}, + { -1, NULL } +}; + +/* SOCKS5 authentication methods */ +#define SOCKS5_AUTH_REJECT 0xFF /* No acceptable auth method */ +#define SOCKS5_AUTH_NOAUTH 0x00 /* without authentication */ +#define SOCKS5_AUTH_GSSAPI 0x01 /* GSSAPI */ +#define SOCKS5_AUTH_USERPASS 0x02 /* User/Password */ +#define SOCKS5_AUTH_CHAP 0x03 /* Challenge-Handshake Auth Proto. */ +#define SOCKS5_AUTH_EAP 0x05 /* Extensible Authentication Proto. */ +#define SOCKS5_AUTH_MAF 0x08 /* Multi-Authentication Framework */ + +#define SOCKS4_REP_SUCCEEDED 90 /* rquest granted (succeeded) */ +#define SOCKS4_REP_REJECTED 91 /* request rejected or failed */ +#define SOCKS4_REP_IDENT_FAIL 92 /* cannot connect identd */ +#define SOCKS4_REP_USERID 93 /* user id not matched */ + +LOOKUP_ITEM socks4_rep_names[] = { + { SOCKS4_REP_SUCCEEDED, "request granted (succeeded)"}, + { SOCKS4_REP_REJECTED, "request rejected or failed"}, + { SOCKS4_REP_IDENT_FAIL, "cannot connect identd"}, + { SOCKS4_REP_USERID, "user id not matched"}, + { -1, NULL } +}; + +#define RESOLVE_UNKNOWN 0 +#define RESOLVE_LOCAL 1 +#define RESOLVE_REMOTE 2 +#define RESOLVE_BOTH 3 +char *resolve_names[] = { "UNKNOWN", "LOCAL", "REMOTE", "BOTH" }; + +int socks_version = 5; /* SOCKS protocol version */ +int socks_resolve = RESOLVE_UNKNOWN; +struct sockaddr_in socks_ns; +char *socks5_auth = NULL; + +/* Environment variable names */ +#define ENV_SOCKS_SERVER "SOCKS_SERVER" /* SOCKS server */ +#define ENV_SOCKS5_SERVER "SOCKS5_SERVER" +#define ENV_SOCKS4_SERVER "SOCKS4_SERVER" + +#define ENV_SOCKS_RESOLVE "SOCKS_RESOLVE" /* resolve method */ +#define ENV_SOCKS5_RESOLVE "SOCKS5_RESOLVE" +#define ENV_SOCKS4_RESOLVE "SOCKS4_RESOLVE" + +#define ENV_SOCKS5_USER "SOCKS5_USER" /* auth user for SOCKS5 */ +#define ENV_SOCKS4_USER "SOCKS4_USER" /* auth user for SOCKS4 */ +#define ENV_SOCKS_USER "SOCKS_USER" /* auth user for SOCKS */ +#define ENV_SOCKS5_PASSWD "SOCKS5_PASSWD" /* auth password for SOCKS5 */ +#define ENV_SOCKS5_PASSWORD "SOCKS5_PASSWORD" /* old style */ + +#define ENV_HTTP_PROXY "HTTP_PROXY" /* common env var */ +#define ENV_HTTP_PROXY_USER "HTTP_PROXY_USER" /* auth user */ +#define ENV_HTTP_PROXY_PASSWORD "HTTP_PROXY_PASSWORD" /* auth password */ + +#define ENV_TELNET_PROXY "TELNET_PROXY" /* common env var */ + +#define ENV_CONNECT_USER "CONNECT_USER" /* default auth user name */ +#define ENV_CONNECT_PASSWORD "CONNECT_PASSWORD" /* default auth password */ + +#define ENV_SOCKS_DIRECT "SOCKS_DIRECT" /* addr-list for non-proxy */ +#define ENV_SOCKS5_DIRECT "SOCKS5_DIRECT" +#define ENV_SOCKS4_DIRECT "SOCKS4_DIRECT" +#define ENV_HTTP_DIRECT "HTTP_DIRECT" +#define ENV_CONNECT_DIRECT "CONNECT_DIRECT" + +#define ENV_SOCKS5_AUTH "SOCKS5_AUTH" +#define ENV_SSH_ASKPASS "SSH_ASKPASS" /* askpass program */ + +/* Prefix string of HTTP_PROXY */ +#define HTTP_PROXY_PREFIX "http://" +#define PROXY_AUTH_NONE 0 +#define PROXY_AUTH_BASIC 1 +#define PROXY_AUTH_DIGEST 2 +int proxy_auth_type = PROXY_AUTH_NONE; + +/* reason of end repeating */ +#define REASON_UNK -2 +#define REASON_ERROR -1 +#define REASON_CLOSED_BY_LOCAL 0 +#define REASON_CLOSED_BY_REMOTE 1 + +/* return value of relay start function. */ +#define START_ERROR -1 +#define START_OK 0 +#define START_RETRY 1 + +/* socket related definitions */ +#ifndef _WIN32 +#define SOCKET int +#endif +#ifndef SOCKET_ERROR +#define SOCKET_ERROR -1 +#endif + +#ifdef _WIN32 +#define socket_errno() WSAGetLastError() +#else /* !_WIN32 */ +#define closesocket close +#define socket_errno() (errno) +#endif /* !_WIN32 */ + +#ifdef _WIN32 +#define popen _popen +#endif /* WIN32 */ + +/* packet operation macro */ +#define PUT_BYTE(ptr,data) (*(unsigned char*)ptr = data) + +/* debug message output */ +void +debug( const char *fmt, ... ) +{ + va_list args; + if ( f_debug ) { + va_start( args, fmt ); + fprintf(stderr, "DEBUG: "); + vfprintf( stderr, fmt, args ); + va_end( args ); + } +} + +void +debug_( const char *fmt, ... ) /* without prefix */ +{ + va_list args; + if ( f_debug ) { + va_start( args, fmt ); + vfprintf( stderr, fmt, args ); + va_end( args ); + } +} + +/* error message output */ +void +error( const char *fmt, ... ) +{ + va_list args; + va_start( args, fmt ); + fprintf(stderr, "ERROR: "); + vfprintf( stderr, fmt, args ); + va_end( args ); +} + +void +fatal( const char *fmt, ... ) +{ + va_list args; + va_start( args, fmt ); + fprintf(stderr, "FATAL: "); + vfprintf( stderr, fmt, args ); + va_end( args ); + exit (EXIT_FAILURE); +} + + +void * +xmalloc (size_t size) +{ + void *ret = malloc(size); + if (ret == NULL) + fatal("Cannot allocate memory: %d bytes.\n", size); + return ret; +} + +char * +downcase( char *str ) +{ + char *buf = str; + while ( *buf ) { + if ( isupper(*buf) ) + *buf += 'a'-'A'; + buf++; + } + return str; /* return converted arg */ +} + +char * +expand_host_and_port (const char *fmt, const char *host, int port) +{ + const char *src; + char *buf, *dst, *ptr; + size_t len = strlen(fmt) + strlen(host) + 20; + buf = xmalloc (len); + dst = buf; + src = fmt; + + while (*src) { + if (*src == '%') { + switch (src[1]) { + case 'h': + strcpy (dst, host); + src += 2; + break; + case 'p': + snprintf (dst, len, "%d", port); + src += 2; + break; + default: + src ++; + break; + } + dst = buf + strlen (buf); + } else if (*src == '\\') { + switch (src[1]) { + case 'r': /* CR */ + *dst++ = '\r'; + src += 2; + break; + case 'n': /* LF */ + *dst++ = '\n'; + src += 2; + break; + case 't': /* TAB */ + *dst++ = '\t'; + src += 2; + break; + default: + src ++; + break; + } + } else { + /* usual */ + *dst++ = *src++; + } + *dst = '\0'; + } + assert (strlen(buf) < len); + return buf; +} + + +int +lookup_resolve( const char *str ) +{ + char *buf = strdup( str ); + int ret; + + downcase( buf ); + if ( strcmp( buf, "both" ) == 0 ) + ret = RESOLVE_BOTH; + else if ( strcmp( buf, "remote" ) == 0 ) + ret = RESOLVE_REMOTE; + else if ( strcmp( buf, "local" ) == 0 ) + ret = RESOLVE_LOCAL; + else if ( strspn(buf, dotdigits) == strlen(buf) ) { +#ifndef WITH_RESOLVER + fatal("Sorry, you can't specify to resolve the hostname with the -R option on Win32 environment."); +#endif /* not WITH_RESOLVER */ + ret = RESOLVE_LOCAL; /* this case is also 'local' */ + socks_ns.sin_addr.s_addr = inet_addr(buf); + socks_ns.sin_family = AF_INET; + } + else + ret = RESOLVE_UNKNOWN; + free(buf); + return ret; +} + +char * +getusername(void) +{ +#ifdef _WIN32 + static char buf[1024]; + DWORD size = sizeof(buf); + buf[0] = '\0'; + GetUserName( buf, &size); + return buf; +#else /* not _WIN32 */ + struct passwd *pw = getpwuid(getuid()); + if ( pw == NULL ) + fatal("getpwuid() failed for uid: %d\n", getuid()); + return pw->pw_name; +#endif /* not _WIN32 */ +} + +/* expect + check STR is begin with substr with case-ignored comparison. + Return 1 if matched, otherwise 0. +*/ +int +expect( char *str, char *substr) +{ + int len = strlen(substr); + while ( 0 < len-- ) { + if ( toupper(*str) != toupper(*substr) ) + return 0; /* not matched */ + str++, substr++; + } + return 1; /* good, matched */ +} + + +/** PARAMETER operation **/ +#define PARAMETER_FILE "/etc/connectrc" +#define PARAMETER_DOTFILE ".connectrc" +typedef struct { + char* name; + char* value; +} PARAMETER_ITEM; +PARAMETER_ITEM parameter_table[] = { + { ENV_SOCKS_SERVER, NULL }, + { ENV_SOCKS5_SERVER, NULL }, + { ENV_SOCKS4_SERVER, NULL }, + { ENV_SOCKS_RESOLVE, NULL }, + { ENV_SOCKS5_RESOLVE, NULL }, + { ENV_SOCKS4_RESOLVE, NULL }, + { ENV_SOCKS5_USER, NULL }, + { ENV_SOCKS5_PASSWD, NULL }, + { ENV_SOCKS5_PASSWORD, NULL }, + { ENV_HTTP_PROXY, NULL }, + { ENV_HTTP_PROXY_USER, NULL }, + { ENV_HTTP_PROXY_PASSWORD, NULL }, + { ENV_CONNECT_USER, NULL }, + { ENV_CONNECT_PASSWORD, NULL }, + { ENV_SSH_ASKPASS, NULL }, + { ENV_SOCKS5_DIRECT, NULL }, + { ENV_SOCKS4_DIRECT, NULL }, + { ENV_SOCKS_DIRECT, NULL }, + { ENV_HTTP_DIRECT, NULL }, + { ENV_CONNECT_DIRECT, NULL }, + { ENV_SOCKS5_AUTH, NULL }, + { NULL, NULL } +}; + +PARAMETER_ITEM* +find_parameter_item(const char* name) +{ + int i; + for( i = 0; parameter_table[i].name != NULL; i++ ){ + if ( strcmp(name, parameter_table[i].name) == 0 ) + return ¶meter_table[i]; + } + return NULL; +} + +void +read_parameter_file_1(const char* name) +{ + FILE* f; + int line; + char lbuf[1025]; + f = fopen(name, "r"); + if( f ){ + debug("Reading parameter file(%s)\n", name); + for ( line = 1; fgets(lbuf, 1024, f); line++ ) { + char *p, *q, *param, *value; + p = strchr(lbuf, '\n'); + if ( p == NULL ) + fatal("%s:%d: buffer overflow\n", name, line); + *p = '\0'; + p = strchr(lbuf, '#'); + if ( p ) + *p = '\0'; + for ( p = lbuf; *p; p++ ) + if( *p != ' ' && *p != '\t' ) break; + if ( *p == '\0' ) continue; + param = p; + p = strchr(p, '='); + if ( p == NULL ) { + error("%s:%d: missing equal sign\n", name, line); + continue; + } + for ( q = p - 1; q >= lbuf; q-- ) + if ( *q != ' ' && *q != '\t' ) break; + *++q = '\0'; + for ( ++p; *p; p++ ) + if ( *p != ' ' && *p != '\t' ) break; + value = p; + for ( ; *p; p++ ); + for ( p--; p >= lbuf; p-- ) + if ( *p != ' ' && *p != '\t' ) break; + *++p = '\0'; + if ( param && value ) { + PARAMETER_ITEM *item; + item = find_parameter_item(param); + if ( item == NULL ) { + error("%s:%d: unknown parameter `%s'\n", name, line, param); + continue; + } + item->value = strdup(value); + debug("Parameter `%s' is set to `%s'\n", param, value); + } + } + } +} + +void +read_parameter_file(void) +{ +#if !defined(_WIN32) || defined(cygwin) + char *name; + struct passwd *pw; +#endif + + read_parameter_file_1(PARAMETER_FILE); +#if !defined(_WIN32) || defined(cygwin) + pw = getpwuid(getuid()); + if ( pw == NULL ) + fatal("getpwuid() failed for uid: %d\n", getuid()); + name = xmalloc(strlen(pw->pw_dir) + strlen(PARAMETER_DOTFILE) + 2); + strcpy(name, pw->pw_dir); + strcat(name, "/" PARAMETER_DOTFILE); + read_parameter_file_1(name); + free(name); +#endif /* _WIN32 */ +} + +char* +getparam(const char* name) +{ + char *value = getenv(name); + if ( value == NULL ){ + PARAMETER_ITEM *item = find_parameter_item(name); + if ( item != NULL ) + value = item->value; + } + return value; +} + + +/** DIRECT connection **/ +#define MAX_DIRECT_ADDR_LIST 256 + +struct ADDRPAIR { + struct in_addr addr; + struct in_addr mask; + char *name; + int negative; +}; + +struct ADDRPAIR direct_addr_list[MAX_DIRECT_ADDR_LIST]; +int n_direct_addr_list = 0; + +void +mask_addr (void *addr, void *mask, int addrlen) +{ + char *a, *m; + a = addr; + m = mask; + while ( 0 < addrlen-- ) + *a++ &= *m++; +} + +int +add_direct_addr (struct in_addr *addr, struct in_addr *mask, int negative) +{ + struct in_addr iaddr; + char *s; + if ( MAX_DIRECT_ADDR_LIST <= n_direct_addr_list ) { + error("direct address table is full!\n"); + return -1; + } + iaddr = *addr; + mask_addr(&iaddr, mask, sizeof(iaddr)); + s = strdup(inet_ntoa(iaddr)); + debug("adding direct addr entry: %s%s/%s\n", + negative? "!": "", s, inet_ntoa(*mask)); + free(s); + memcpy( &direct_addr_list[n_direct_addr_list].addr, + &iaddr, sizeof(iaddr)); + memcpy( &direct_addr_list[n_direct_addr_list].mask, + mask, sizeof(*mask)); + direct_addr_list[n_direct_addr_list].name = NULL; + direct_addr_list[n_direct_addr_list].negative = negative; + n_direct_addr_list++; + return 0; +} + + +/* add domain/host name entry to direct name table */ +int +add_direct_host( const char *name, int negative) +{ + if ( MAX_DIRECT_ADDR_LIST <= n_direct_addr_list ) { + error("direct address table is full!\n"); + return -1; + } + if (*name == '*') + name++; + if (*name == '.') + name++; + debug("adding direct name entry: %s%s\n", negative? "!": "", name); + direct_addr_list[n_direct_addr_list].name = downcase(strdup(name)); + direct_addr_list[n_direct_addr_list].negative = negative; + n_direct_addr_list++; + return 0; +} + + +int +parse_addr_pair (const char *str, struct in_addr *addr, struct in_addr *mask) +{ + /* NOTE: */ + /* Assume already be splitted by separator + and formatted as folowing: + 1) 12.34.56.789/255.255.255.0 + 2) 12.34.56.789/24 + 3) 12.34.56. + All above generates same addr/mask pair 12.34.56.0 and 255.255.255.0 + */ + const char *ptr; + u_char *dsta, *dstm; + int i, n; + + assert( str != NULL ); + addr->s_addr = 0; + mask->s_addr = 0; + ptr = str; + dsta = (u_char*)&addr->s_addr; + dstm = (u_char*)&mask->s_addr; + for (i=0; i<4; i++ ) { + if ( *ptr == '\0' ) + break; /* case of format #3 */ + if ( !isdigit(*ptr) ) + return -1; /* format error: */ + *dsta++ = atoi( ptr ); + *dstm++ = 255; /* automatic mask for format #3 */ + while ( isdigit(*ptr) ) /* skip digits */ + ptr++; + if ( *ptr == '.' ) + ptr++; + else + break; + } + /* At this point, *ptr points '/' or EOS ('\0') */ + if ( *ptr == '\0' ) + return 0; /* complete as format #3 */ + if ( *ptr != '/' ) + return -1; /* format error */ + /* Now parse mask for format #1 or #2 */ + ptr++; + mask->s_addr = 0; /* clear automatic mask */ + + if ( strchr( ptr, '.') ) { + /* case of format #1 */ + dstm = (u_char*)&mask->s_addr; + for (i=0; i<4; i++) { + if ( !isdigit(*ptr) ) + return -1; /* format error: */ + *dstm++ = atoi(ptr); + while ( isdigit(*ptr) ) /* skip digits */ + ptr++; + if ( *ptr == '.' ) + ptr++; + else + break; /* from for loop */ + } + /* complete as format #1 */ + } else { + /* case of format #2 */ + if ( !isdigit(*ptr) ) + return -1; /* format error: */ + n = atoi(ptr); + if ( n<0 || 32s_addr = (n==0)? 0: htonl(((u_long)0xFFFFFFFF)<<(32-n)); + /* complete as format #1 */ + } + return 0; +} + +void +initialize_direct_addr (void) +{ + int negative; + int n_entries; + char *env = NULL, *beg, *next, *envkey = NULL; + struct in_addr addr, mask; + + if ( relay_method == METHOD_SOCKS ){ + if ( socks_version == 5 ) + envkey = ENV_SOCKS5_DIRECT; + else + envkey = ENV_SOCKS4_DIRECT; + env = getparam(envkey); + if ( env == NULL ) + env = getparam(ENV_SOCKS_DIRECT); + } else if ( relay_method == METHOD_HTTP ){ + env = getparam(ENV_HTTP_DIRECT); + } + + if ( env == NULL ) + env = getparam(ENV_CONNECT_DIRECT); + + if ( env == NULL ) + return; /* no entry */ + debug("making direct addr list from: '%s'\n", env); + env = strdup( env ); /* reallocate to modify */ + beg = next = env; + n_entries = 0; + do { + if ( MAX_DIRECT_ADDR_LIST <= n_entries ) { + error("too many entries in %s", envkey); + break; /* from do loop */ + } + next = strchr( beg, ','); + if ( next != NULL ) + *next++ = '\0'; + addr.s_addr = 0; + mask.s_addr = 0; + if (*beg == '!') { + negative = 1; + beg++; + } else + negative = 0; + if ( !parse_addr_pair( beg, &addr, &mask ) ) { + add_direct_addr( &addr, &mask, negative ); + } else { + add_direct_host( beg, negative ); + } + if ( next != NULL ) + beg = next; + } while ( next != NULL ); + + free( env ); + return; +} + +int +cmp_addr (void *addr1, void *addr2, int addrlen) +{ + return memcmp( addr1, addr2, addrlen ); +} + +int +is_direct_address (const struct in_addr addr) +{ + int i, neg; + struct in_addr iaddr; + + /* Note: assume IPV4 address !! */ + for (i=0; i 1 (exact match) + ends_with("foo.bar.com", "bar.com") => 1 (domain match) + ends_with("foo.beebar.com", "bar.com") => 0 (partial match) + ends_with("bar", "bar.com") => 0 (shorter) + */ +domain_match(const char *s1, const char *s2) +{ + int len1, len2; + const char *tail1, *tail2; + len1 = strlen(s1); + len2 = strlen(s2); + if (len1 < len2 || len1 == 0 || len2 == 0) + return 0; /* not match */ + tail1 = s1 + len1; + tail2 = s2 + len2; + while (0 < len1 && 0 < len2) { + if (*--tail1 != *--tail2) + break; /* not match */ + len1--, len2--; + } + if (len2 != 0) + return 0; /* not match */ + /* Now exact match, domain match or partial match. + Return true if exact or domain match. + Or continue checking. */ + if (tail1 == s1 || tail1[-1] == '.') + return 1; /* match! */ + return 0; /* not match */ +} + +/* Check given NAME is ends with one of + registered direct name entry. + Return 1 if matched, or 0. +*/ +int +is_direct_name (const char *name) +{ + int len, i; + const char *tail; + debug("checking %s is for direct?\n", name); + name = downcase(strdup(name)); + len = strlen(name); + if (len < 1) + return 0; /* false */ + tail = &name[len]; + for (i=0; is_port); + debug("service: %s => %d\n", service, port); + } + } + return (u_short)port; +} + +void +make_revstr(void) +{ + char *ptr; + size_t len; + ptr = strstr(rcs_revstr, ": "); + if (!ptr) { + revstr = strdup("unknown"); + return; + } + ptr += 2; + /* assume subversion's keyword expansion like "Revision: 96". */ + minor_version = atoi(ptr); + revstr = xmalloc(20); + snprintf(revstr, 20, "%d.%d", major_version, minor_version); +} + +int +getarg( int argc, char **argv ) +{ + int err = 0; + char *ptr, *server = (char*)NULL; + int method = METHOD_DIRECT; + + progname = *argv; + argc--, argv++; + + /* check optinos */ + while ( (0 < argc) && (**argv == '-') ) { + ptr = *argv + 1; + while ( *ptr ) { + switch ( *ptr ) { + case 's': /* use SOCKS */ + method = METHOD_SOCKS; + break; + + case 'n': /* no proxy */ + method = METHOD_DIRECT; + break; + + case 'h': /* use http-proxy */ + method = METHOD_HTTP; + break; + case 't': + method = METHOD_TELNET; + break; + + case 'S': /* specify SOCKS server */ + if ( 1 < argc ) { + argv++, argc--; + method = METHOD_SOCKS; + server = *argv; + } else { + error("option '-%c' needs argument.\n", *ptr); + err++; + } + break; + + case 'H': /* specify http-proxy server */ + if ( 1 < argc ) { + argv++, argc--; + method = METHOD_HTTP; + server = *argv; + } else { + error("option '-%c' needs argument.\n", *ptr); + err++; + } + break; + case 'T': /* specify telnet proxy server */ + if ( 1 < argc ) { + argv++, argc--; + method = METHOD_TELNET; + server = *argv; + } else { + error("option '-%c' needs argument.\n", *ptr); + err++; + } + break; + + case 'c': + if (1 < argc) { + argv++, argc--; + telnet_command = *argv; + } else { + error("option '%c' needs argument.\n", *ptr); + err++; + } + break; + + case 'P': + f_hold_session = 1; + /* without break */ + case 'p': /* specify port to forward */ + if ( 1 < argc ) { + argv++, argc--; + local_type = LOCAL_SOCKET; + local_port = resolve_port(*argv); + } else { + error("option '-%c' needs argument.\n", *ptr); + err++; + } + break; + +#ifndef _WIN32 + case 'w': + if ( 1 < argc ) { + argv++, argc--; + connect_timeout = atoi(*argv); + } else { + error("option '-%c' needs argument.\n", *ptr); + err++; + } + break; +#endif /* not _WIN32 */ + + case '4': + socks_version = 4; + break; + + case '5': + socks_version = 5; + break; + + case 'a': + if ( 1 < argc ) { + argv++, argc--; + socks5_auth = *argv; + } else { + error("option '-%c' needs argument.\n", *ptr); + err++; + } + break; + + case 'R': /* specify resolve method */ + if ( 1 < argc ) { + argv++, argc--; + socks_resolve = lookup_resolve( *argv ); + } else { + error("option '-%c' needs argument.\n", *ptr); + err++; + } + break; + + case 'V': /* print version */ + fprintf(stderr, "%s\nVersion %s\n", progdesc, revstr); + exit(0); + + case 'd': /* debug mode */ + f_debug++; + break; + + default: + error("unknown option '-%c'\n", *ptr); + err++; + } + ptr++; + } + argc--, argv++; + } + + /* check error */ + if ( 0 < err ) + goto quit; + + set_relay( method, server ); + + /* check destination HOST (MUST) */ + if ( argc == 0 ) { + fprintf(stderr, "%s\nVersion %s\n", progdesc, revstr); + fprintf(stderr, usage, progname); + exit(0); + } + dest_host = argv[0]; + /* decide port or service name from programname or argument */ + if ( ((ptr=strrchr( progname, '/' )) != NULL) || + ((ptr=strchr( progname, '\\')) != NULL) ) + ptr++; + else + ptr = progname; + if ( dest_port == 0 ) { + /* accept only if -P is not specified. */ + if ( 1 < argc ) { + /* get port number from argument (prior to progname) */ + /* NOTE: This way is for cvs ext method. */ + dest_port = resolve_port(argv[1]); + } else if ( strncmp( ptr, "connect-", 8) == 0 ) { + /* decide port number from program name */ + char *str = strdup( ptr+8 ); + str[strcspn( str, "." )] = '\0'; + dest_port = resolve_port(str); + free(str); + } + } + /* check port number */ + if ( dest_port <= 0 ) { + error( "You must specify the destination port correctly.\n"); + err++; + goto quit; + } + if ( (relay_method != METHOD_DIRECT) && (relay_port <= 0) ) { + error("Invalid relay port: %d\n", dest_port); + err++; + goto quit; + } + +quit: + /* report for debugging */ + debug("relay_method = %s (%d)\n", + method_names[relay_method], relay_method); + if ( relay_method != METHOD_DIRECT ) { + debug("relay_host=%s\n", relay_host); + debug("relay_port=%d\n", relay_port); + debug("relay_user=%s\n", relay_user); + } + if ( relay_method == METHOD_SOCKS ) { + debug("socks_version=%d\n", socks_version); + debug("socks_resolve=%s (%d)\n", + resolve_names[socks_resolve], socks_resolve); + } + debug("local_type=%s\n", local_type_names[local_type]); + if ( local_type == LOCAL_SOCKET ) { + debug("local_port=%d\n", local_port); + if (f_hold_session) + debug (" with holding remote session.\n"); + } + debug("dest_host=%s\n", dest_host); + debug("dest_port=%d\n", dest_port); + if ( 0 < err ) { + fprintf(stderr, usage, progname); + exit(1); + } + return 0; +} + +#ifndef _WIN32 +/* Time-out feature is not allowed for Win32 native compilers. */ +/* MSVC and Borland C cannot but Cygwin and UNIXes can. */ + +/* timeout signal hander */ +void +sig_timeout(void) +{ + signal( SIGALRM, SIG_IGN ); + alarm( 0 ); + error( "timed out\n" ); + exit(1); +} + +/* set timeout param = seconds, 0 clears */ +void +set_timeout(int timeout) +{ + /* This feature is allowed for UNIX or cygwin environments, currently */ + if ( timeout == 0 ) { + debug( "clearing timeout\n" ); + signal( SIGALRM, SIG_IGN ); + alarm( 0 ); + } else { + debug( "setting timeout: %d seconds\n", timeout ); + signal(SIGALRM, (void *)sig_timeout); + alarm( timeout ); + } +} +#endif + +#if !defined(_WIN32) && !defined(__CYGWIN32__) +void +switch_ns (struct sockaddr_in *ns) +{ + res_init(); + memcpy (&_res.nsaddr_list[0], ns, sizeof(*ns)); + _res.nscount = 1; + debug("Using nameserver at %s\n", inet_ntoa(ns->sin_addr)); +} +#endif /* !_WIN32 && !__CYGWIN32__ */ + +/* TODO: IPv6 + TODO: fallback if askpass execution failed. + */ + +int +local_resolve (const char *host, struct sockaddr_in *addr) +{ + struct hostent *ent; + if ( strspn(host, dotdigits) == strlen(host) ) { + /* given by IPv4 address */ + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = inet_addr(host); + } else { + debug("resolving host by name: %s\n", host); + ent = gethostbyname (host); + if ( ent ) { + memcpy (&addr->sin_addr, ent->h_addr, ent->h_length); + addr->sin_family = ent->h_addrtype; + debug("resolved: %s (%s)\n", + host, inet_ntoa(addr->sin_addr)); + } else { + debug("failed to resolve locally.\n"); + return -1; /* failed */ + } + } + return 0; /* good */ +} + +int +open_connection( const char *host, u_short port ) +{ + SOCKET s; + struct sockaddr_in saddr; + + /* resolve address of proxy or direct target */ + if (local_resolve (host, &saddr) < 0) { + error("can't resolve hostname: %s\n", host); + return SOCKET_ERROR; + } + saddr.sin_port = htons(port); + + debug("connecting to %s:%u\n", inet_ntoa(saddr.sin_addr), port); + s = socket( AF_INET, SOCK_STREAM, 0 ); + if ( connect( s, (struct sockaddr *)&saddr, sizeof(saddr)) + == SOCKET_ERROR) { + debug( "connect() failed.\n"); + return SOCKET_ERROR; + } + return s; +} + +void +report_text( char *prefix, char *buf ) +{ + static char work[1024]; + char *tmp; + + if ( !f_debug ) + return; + if ( !f_report ) + return; /* don't report */ + debug("%s \"", prefix); + while ( *buf ) { + memset( work, 0, sizeof(work)); + tmp = work; + while ( *buf && ((tmp-work) < (int)sizeof(work)-5) ) { + switch ( *buf ) { + case '\t': *tmp++ = '\\'; *tmp++ = 't'; break; + case '\r': *tmp++ = '\\'; *tmp++ = 'r'; break; + case '\n': *tmp++ = '\\'; *tmp++ = 'n'; break; + case '\\': *tmp++ = '\\'; *tmp++ = '\\'; break; + default: + if ( isprint(*buf) ) { + *tmp++ = *buf; + } else { + int consumed = tmp - work; + snprintf( tmp, sizeof(work)-consumed, + "\\x%02X", (unsigned char)*buf); + tmp += strlen(tmp); + } + } + buf++; + *tmp = '\0'; + } + debug_("%s", work); + } + + debug_("\"\n"); +} + + +void +report_bytes( char *prefix, char *buf, int len ) +{ + if ( ! f_debug ) + return; + debug( "%s", prefix ); + while ( 0 < len ) { + fprintf( stderr, " %02x", *(unsigned char *)buf); + buf++; + len--; + } + fprintf(stderr, "\n"); + return; +} + +int +atomic_out( SOCKET s, char *buf, int size ) +{ + int ret, len; + + assert( buf != NULL ); + assert( 0<=size ); + /* do atomic out */ + ret = 0; + while ( 0 < size ) { + len = send( s, buf+ret, size, 0 ); + if ( len == -1 ) + fatal("atomic_out() failed to send(), %d\n", socket_errno()); + ret += len; + size -= len; + } + if (!f_report) { + debug("atomic_out() [some bytes]\n"); + debug(">>> xx xx xx xx ...\n"); + } else { + debug("atomic_out() [%d bytes]\n", ret); + report_bytes(">>>", buf, ret); + } + return ret; +} + +int +atomic_in( SOCKET s, char *buf, int size ) +{ + int ret, len; + + assert( buf != NULL ); + assert( 0<=size ); + + /* do atomic in */ + ret = 0; + while ( 0 < size ) { + len = recv( s, buf+ret, size, 0 ); + if ( len == -1 ) { + fatal("atomic_in() failed to recv(), %d\n", socket_errno()); + } else if ( len == 0 ) { + fatal( "Connection closed by peer.\n"); + } + ret += len; + size -= len; + } + if (!f_report) { + debug("atomic_in() [some bytes]\n"); + debug("<<< xx xx xx xx ...\n"); + } else { + debug("atomic_in() [%d bytes]\n", ret); + report_bytes("<<<", buf, ret); + } + return ret; +} + +int +line_input( SOCKET s, char *buf, int size ) +{ + char *dst = buf; + if ( size == 0 ) + return 0; /* no error */ + size--