Picon

Old ipv6 patch still necessary?

Hello,
I have a questions about the implementation of busybox. I'm one of the
Android developer from the firewall project AFWall+ and actually we
use an ipv6_route.h patch from Tias Guns.

Project:

https://github.com/ukanth/afwall

Patch (original designed by Tias Guns <tias <at> ulyssis.org>)

From c04d001c962e756d152abc1dbd58edfdbfee45a1 Mon Sep 17 00:00:00 2001
From: Tias Guns <tias <at> ulyssis.org>
Date: Mon, 19 Mar 2012 18:24:29 +0000
Subject: [PATCH] fix ipv6, add ipv6_route.h
from 'in6_rtmsg' by Dan Drown
"in6_rtmsg defined in linux/ipv6_route.h"
http://dan.drown.org/android/src/busybox/
---
 include/linux/ipv6_route.h | 58 ++++++++++++++++++++++++++++++++++++++++++++
 networking/ifconfig.c | 2 +
 networking/route.c | 2 +
 3 files changed, 62 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/ipv6_route.h
diff --git a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h
new file mode 100644
index 0000000..144875d
--- /dev/null
+++ b/include/linux/ipv6_route.h
 <at>  <at>  -0,0 +1,58  <at>  <at> 
(Continue reading)

Timo Teras | 20 Jul 10:20 2014
Picon
Picon

Re: [PATCH] top: fix parsing of /proc/meminfo

On Sat, 19 Jul 2014 21:31:33 +0200
Dan Fandrich <dan <at> coneharvesters.com> wrote:

> On Fri, Jul 18, 2014 at 10:07:06PM +0300, Timo Teräs wrote:
> > and do it in smaller code:
> > 
> > diff --git a/procps/top.c b/procps/top.c
> > index 530f45f..e60dab6 100644
> > --- a/procps/top.c
> > +++ b/procps/top.c
> >  <at>  <at>  -501,10 +501,27  <at>  <at>  static void display_cpus(int scr_width, char
> > *scrbuf, int *lines_rem_p) 
> >  static unsigned long display_header(int scr_width, int
> > *lines_rem_p) {
> > +	static const char *fields =
> 
> Minor suggestion: this should be 
> 	static const char * const fields =
> 
> so it can go into .rodata.

It does go into .rodata already as-is. In fact 'make bloatcheck' says
there's no difference on sizes depending which form is used. I guess
this is due to compiler optimization figuring out that it's used only
locally in the function.

That said, adding the second "const" does make sense. And thinking more,
"static" should probably be left out.

I can post new version if so wanted.
(Continue reading)

Timo Teräs | 18 Jul 21:07 2014
Picon
Picon

[PATCH] top: fix parsing of /proc/meminfo

and do it in smaller code:

function                                             old     new   delta
.rodata                                           120254  120205     -49
display_process_list                                1705    1563    -142
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-191)           Total: -191 bytes

Signed-off-by: Timo Teräs <timo.teras <at> iki.fi>
---
 procps/top.c | 80 +++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 44 insertions(+), 36 deletions(-)

diff --git a/procps/top.c b/procps/top.c
index 530f45f..e60dab6 100644
--- a/procps/top.c
+++ b/procps/top.c
 <at>  <at>  -501,10 +501,27  <at>  <at>  static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p)

 static unsigned long display_header(int scr_width, int *lines_rem_p)
 {
+	static const char *fields =
+		"MemTotal\0"
+		"MemFree\0"
+		"Shmem\0"
+		"Buffers\0"
+		"Cached\0"
+		"Mem\0";
+	enum {
+		Hdr_Total,
(Continue reading)

Michael Tokarev | 18 Jul 11:50 2014
Picon

[PATCH] iproute: support onelink route option and print route flags

Signed-off-by: Michael Tokarev <mjt <at> tls.msk.ru>
---
 networking/libiproute/iproute.c |   18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index ec4d8ba..273f6fe 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
 <at>  <at>  -298,6 +298,19  <at>  <at>  static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
 	if (tb[RTA_PRIORITY]) {
 		printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
 	}
+	if (r->rtm_flags & RTNH_F_DEAD) {
+		printf("dead ");
+	}
+	if (r->rtm_flags & RTNH_F_ONLINK) {
+		printf("onlink ");
+	}
+	if (r->rtm_flags & RTNH_F_PERVASIVE) {
+		printf("pervasive ");
+	}
+	if (r->rtm_flags & RTM_F_NOTIFY) {
+		printf("notify ");
+	}
+
 	if (r->rtm_family == AF_INET6) {
 		struct rta_cacheinfo *ci = NULL;
 		if (tb[RTA_CACHEINFO]) {
 <at>  <at>  -330,7 +343,7  <at>  <at>  static int iproute_modify(int cmd, unsigned flags, char **argv)
(Continue reading)

Ben Shelton | 17 Jul 18:34 2014

[PATCH] zcip: fix link-local IP conflict detection

From: Ken Sharp <ken.sharp <at> ni.com>

During link-local IP resolution, if a regular ARP request is received
during the ARP probe period, it will incorrectly cause a target IP
conflict.  This then leads to a new IP being picked unnecessarily.

Per RFC 3927, section 2.2.1, we should flag a target IP conflict only if
the source IP is null, the target IP matches our IP, and the source
hw addr does not match our hw addr.

Signed-off-by: Ken Sharp <ken.sharp <at> ni.com>
Signed-off-by: Ben Shelton <ben.shelton <at> ni.com>
---

Note that we reproduced the issue and tested the fix on an ARM A9-based 
board as follows:

- Connect two machines via a crossover cable or on a network with no DHCP 
  server available.
- Continuously ping the machine running busybox from the other
- Reboot the busybox machine (the one being pinged)
- When the busybox machine comes back up it will have a different IP 
  address because of the incorrect target IP conflict

 networking/zcip.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/networking/zcip.c b/networking/zcip.c
index 7314ff8..cdb6bcd 100644
--- a/networking/zcip.c
(Continue reading)

ram kumar | 16 Jul 15:40 2014

How to get values returned to udhcpc from dhcp server

Please help, need help with udhcpc....


I have requested for option 43 by sending my vendor class, the dhcp server is correctly sending the vendor specific IP address that I have given in config file , Im able to see this through wireshark...now how do I access the IP from udhcpc?? where does udhcpc store values returned by the dhcp server..


any help would be really appreciated..

ram
_______________________________________________
busybox mailing list
busybox <at> busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
Jeremy Kerr | 15 Jul 05:03 2014

[PATCH resend] udhcp: add PXELINUX path prefix option (code 210) definition

Like d3092c99, this change adds support for the DHCP "path-prefix"
option, as defined in RFC 5071. We use the string identifer
"pxepathprefix".

Adding this option makes string parsing in the hook scripts simpler.

Signed-off-by: Jeremy Kerr <jk <at> ozlabs.org>

---
 networking/udhcp/common.c |    2 ++
 networking/udhcp/common.h |    1 +
 2 files changed, 3 insertions(+)

diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index fe322db..bc41c8d 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
 <at>  <at>  -63,6 +63,7  <at>  <at>  const struct dhcp_optflag dhcp_optflags[] = {
 	{ OPTION_U8                               , 0x85 }, /* DHCP_VLAN_PRIORITY */
 #endif
 	{ OPTION_STRING                           , 0xd1 }, /* DHCP_PXE_CONF_FILE */
+	{ OPTION_STRING                           , 0xd2 }, /* DHCP_PXE_PATH_PREFIX */
 	{ OPTION_6RD                              , 0xd4 }, /* DHCP_6RD           */
 	{ OPTION_STATIC_ROUTES | OPTION_LIST      , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
 	{ OPTION_STRING                           , 0xfc }, /* DHCP_WPAD          */
 <at>  <at>  -130,6 +131,7  <at>  <at>  const char dhcp_option_strings[] ALIGN1 =
 	"vlanpriority" "\0"/* DHCP_VLAN_PRIORITY  */
 #endif
 	"pxeconffile" "\0" /* DHCP_PXE_CONF_FILE  */
+	"pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX  */
 	"ip6rd" "\0"       /* DHCP_6RD            */
 	"msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
 	"wpad" "\0"        /* DHCP_WPAD           */
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 5e70d60..e5e0f25 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
 <at>  <at>  -152,6 +152,7  <at>  <at>  enum {
 //#define DHCP_VLAN_ID          0x84 /* 802.1P VLAN ID */
 //#define DHCP_VLAN_PRIORITY    0x85 /* 802.1Q VLAN priority */
 //#define DHCP_PXE_CONF_FILE    0xd1 /* RFC 5071 Configuration File */
+//#define DHCP_PXE_PATH_PREFIX  0xd2 /* RFC 5071 Configuration File */
 //#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
 //#define DHCP_WPAD             0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
 #define DHCP_END                0xff
Timo Teras | 14 Jul 12:48 2014
Picon
Picon

top buffers/cached values are bogus on new kernels

Hi,

On new kernels (3.14+) the buffers and cached fields for 'top' applet
are bogus.

procps/top.c:display_header() parses /proc/meminfo directly, and it
works only if the expected fields come in the expected order. For 3.14
MemAvailable field was added after MemFree[1]; and that broke the code.
It would probably make sense to write the code in more generic form so
the order of the fields does not matter.

- Timo

[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
Stefani Seibold | 7 Jul 15:49 2014
Picon

Fast CGI for busybox

Hi,

this patch add Fast CGI Support to the busybox httpd web server. I hope you like it ;-)

To connect a extension to a fast CGI socket add a
*.<extension>: <at> <path to fcgi socket>
to the httpd.conf

The patch is against busybox 1.22.1

Greetings,
Stefani

diff -u -N -r -p busybox-1.22.1.orig/networking/httpd.c busybox-1.22.1/networking/httpd.c
--- busybox-1.22.1/networking/httpd.c	2014-01-09 19:15:44.000000000 +0100
+++ busybox-1.22.1/networking/httpd.c	2014-07-04 09:37:56.128167910 +0200
 <at>  <at>  -136,6 +136,10  <at>  <at> 
 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
 # include <sys/sendfile.h>
 #endif
+#if ENABLE_FEATURE_HTTPD_FAST_CGI
+# include <sys/un.h>
+#endif
+
 /* amount of buffering in a pipe */
 #ifndef PIPE_BUF
 # define PIPE_BUF 4096
 <at>  <at>  -955,10 +959,16  <at>  <at>  static void send_headers(int responseNum
 	/* emit the current date */
 	strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&timer));
 	len = sprintf(iobuf,
-			"HTTP/1.0 %d %s\r\nContent-type: %s\r\n"
-			"Date: %s\r\nConnection: close\r\n",
-			responseNum, responseString, mime_type, tmp_str);
+			"HTTP/1.0 %d %s\r\n"
+			"Date: %s\r\n"
+			"Connection: close\r\n"
+			"Content-Type: %s",
+			responseNum, responseString, tmp_str, mime_type);

+	if (infoString) {
+			len += sprintf(iobuf + len, "; charset=iso-8859-1");
+	}
+	len += sprintf(iobuf + len, "\r\n");
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
 	if (responseNum == HTTP_UNAUTHORIZED) {
 		len += sprintf(iobuf + len,
 <at>  <at>  -1009,7 +1019,7  <at>  <at>  static void send_headers(int responseNum
 		);
 	}

-	if (content_gzip)
+	if (content_gzip && !infoString)
 		len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n");

 	iobuf[len++] = '\r';
 <at>  <at>  -1263,6 +1273,520  <at>  <at>  static NOINLINE void cgi_io_loop_and_exi
 }
 #endif

+#if ENABLE_FEATURE_HTTPD_FAST_CGI
+
+/*
+ * Error codes.  Assigned to avoid conflict with EOF and errno(2).
+ */
+#define FCGX_UNSUPPORTED_VERSION -2
+#define FCGX_PROTOCOL_ERROR -3
+
+typedef struct {
+	unsigned char version;
+	unsigned char type;
+	unsigned char requestIdB1;
+	unsigned char requestIdB0;
+	unsigned char contentLengthB1;
+	unsigned char contentLengthB0;
+	unsigned char paddingLength;
+	unsigned char reserved;
+} FCGI_Header;
+
+/*
+ * Number of bytes in a FCGI_Header.  Future versions of the protocol
+ * will not reduce this number.
+ */
+#define FCGI_HEADER_LEN		8
+
+/*
+ * Value for version component of FCGI_Header
+ */
+#define FCGI_VERSION_1		1
+
+/*
+ * Values for type component of FCGI_Header
+ */
+#define FCGI_BEGIN_REQUEST	1
+#define FCGI_ABORT_REQUEST	2
+#define FCGI_END_REQUEST	3
+#define FCGI_PARAMS		4
+#define FCGI_STDIN		5
+#define FCGI_STDOUT		6
+#define FCGI_STDERR		7
+#define FCGI_DATA		8
+#define FCGI_GET_VALUES		9
+#define FCGI_GET_VALUES_RESULT  10
+#define FCGI_UNKNOWN_TYPE	11
+#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
+
+/*
+ * Value for requestId component of FCGI_Header
+ */
+#define FCGI_NULL_REQUEST_ID	0
+
+typedef struct {
+	unsigned char roleB1;
+	unsigned char roleB0;
+	unsigned char flags;
+	unsigned char reserved[5];
+} FCGI_BeginRequestBody;
+
+/*
+ * Mask for flags component of FCGI_BeginRequestBody
+ */
+#define FCGI_KEEP_CONN		1
+
+/*
+ * Values for role component of FCGI_BeginRequestBody
+ */
+#define FCGI_RESPONDER		1
+#define FCGI_AUTHORIZER		2
+#define FCGI_FILTER		3
+
+typedef struct {
+	unsigned char appStatusB3;
+	unsigned char appStatusB2;
+	unsigned char appStatusB1;
+	unsigned char appStatusB0;
+	unsigned char protocolStatus;
+	unsigned char reserved[3];
+} FCGI_EndRequestBody;
+
+/*
+ * Values for protocolStatus component of FCGI_EndRequestBody
+ */
+#define FCGI_REQUEST_COMPLETE	0
+#define FCGI_CANT_MPX_CONN	1
+#define FCGI_OVERLOADED		2
+#define FCGI_UNKNOWN_ROLE	3
+
+/*
+ * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records
+ */
+#define FCGI_MAX_CONNS  "FCGI_MAX_CONNS"
+#define FCGI_MAX_REQS   "FCGI_MAX_REQS"
+#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"
+
+static const unsigned short requestId = 1;
+
+static void * fcgi_flush_param(int sockfd, unsigned char *buf)
+{
+	FCGI_Header *header = (FCGI_Header *)iobuf;
+	unsigned short clen = buf - (unsigned char *)iobuf - sizeof(*header);
+	unsigned int len = (clen + 7) & ~7;
+
+	header->contentLengthB1 = clen >> 8;
+	header->contentLengthB0 = clen;
+	header->paddingLength = len - clen;
+
+	memset(buf, 0, len - clen);
+
+	len += sizeof(*header);
+
+	if (full_write(sockfd, iobuf, len) != len)
+		log_and_exit();
+
+	return iobuf + sizeof(*header);
+}
+
+static void * fcgi_store(int sockfd, unsigned char *buf, unsigned char v)
+{
+	if (buf - (unsigned char *)iobuf >= IOBUF_SIZE)
+		buf = fcgi_flush_param(sockfd, buf);
+	
+	*buf++ = v;
+
+	return buf;
+}
+
+static void * fcgi_store_len(int sockfd, unsigned char *buf, unsigned int len)
+{
+	if (len < 0x80) {
+		buf = fcgi_store(sockfd, buf, len);
+	} else {
+		buf = fcgi_store(sockfd, buf, (len >> 24) | 0x80);
+		buf = fcgi_store(sockfd, buf, len >> 16);
+		buf = fcgi_store(sockfd, buf, len >> 8);
+		buf = fcgi_store(sockfd, buf, len);
+	}
+	return buf;
+}
+
+static void * fcgi_set_param(int sockfd, unsigned char *buf, char *env, unsigned int nameLen, unsigned
int valueLen)
+{
+	buf = fcgi_store_len(sockfd, buf, nameLen);
+	buf = fcgi_store_len(sockfd, buf, valueLen);
+
+	while(nameLen--)
+		buf = fcgi_store(sockfd, buf, *env++);
+	env++;
+	while(valueLen--)
+		buf = fcgi_store(sockfd, buf, *env++);
+
+	return buf;
+}
+
+static void * fcgi_begin_request(void *buf, unsigned short role, int keepConnection)
+{
+	FCGI_BeginRequestBody *body = buf;
+
+	body->roleB1 = role >> 8;
+	body->roleB0 = role;
+	body->flags  = keepConnection ? FCGI_KEEP_CONN : 0;
+	memset(&body->reserved, 0, sizeof(body->reserved));
+
+	return buf + sizeof(*body);
+}
+
+static void _fcgi_make_header(FCGI_Header *header, unsigned char type, unsigned short
contentLength, unsigned char paddingLength)
+{
+	header->version = FCGI_VERSION_1;
+	header->type = type;
+	header->requestIdB1 = requestId >> 8;
+	header->requestIdB0 = requestId;
+	header->contentLengthB1 = contentLength >> 8;
+	header->contentLengthB0 = contentLength;
+	header->paddingLength = paddingLength;
+	header->reserved =  0;
+}
+
+static void * fcgi_make_header(unsigned char type, unsigned short contentLength, unsigned char paddingLength)
+{
+	FCGI_Header *header = (FCGI_Header *)iobuf;
+
+	_fcgi_make_header(header, type, contentLength, paddingLength);
+
+	return iobuf + sizeof(*header);
+}
+
+/* gcc 4.2.1 fares better with NOINLINE */
+static NOINLINE void fcgi_io_loop_and_exit(int sockfd, int post_len) NORETURN;
+static NOINLINE void fcgi_io_loop_and_exit(int sockfd, int post_len)
+{
+	struct pollfd pfd[2];
+	int out_cnt; /* we buffer a bit of initial CGI output */
+	const int init_len = 8;
+	unsigned int rbuf_cnt;
+	int count;
+	FCGI_Header toFCGIhdr, fromFCGIhdr;
+	unsigned int toFCGIhdr_cnt, fromFCGIhdr_cnt;
+	unsigned int clen, plen;
+	char *rbuf = NULL;
+	int read_flag;
+
+	_fcgi_make_header(&toFCGIhdr, FCGI_STDIN, hdr_cnt, 0);
+	toFCGIhdr_cnt = sizeof(toFCGIhdr);
+	fromFCGIhdr_cnt = 0;
+	clen = 0;
+	plen = 0;
+
+	/* iobuf is used for CGI -> network data,
+	 * hdr_buf is for network -> CGI data (POSTDATA) */
+
+	/* If CGI dies, we still want to correctly finish reading its output
+	 * and send it to the peer. So please no SIGPIPEs! */
+	signal(SIGPIPE, SIG_IGN);
+
+	// We inconsistently handle a case when more POSTDATA from network
+	// is coming than we expected. We may give *some part* of that
+	// extra data to CGI.
+
+	/* NB: breaking out of this loop jumps to log_and_exit() */
+	out_cnt = 0;
+	rbuf_cnt = 0;
+
+	while (1) {
+		memset(pfd, 0, sizeof(pfd));
+
+		pfd[1].fd = sockfd;
+		pfd[1].events = POLLIN;
+
+		if (toFCGIhdr_cnt || hdr_cnt)  {
+			pfd[1].events |= POLLOUT;
+		} else {
+			if (post_len > 0)
+				pfd[0].events = POLLIN;
+		}
+
+		/* Now wait on the set of sockets */
+		count = safe_poll(pfd, 2, -1);
+		if (count <= 0)
+			break;
+
+		if (pfd[0].revents) {
+			/* post_len > 0 && hdr_cnt == 0 here */
+			/* We expect data, prev data portion is eaten by CGI
+			 * and there *is* data to read from the peer
+			 * (POSTDATA) */
+			count = safe_read(STDIN_FILENO, hdr_buf, sizeof(hdr_buf));
+			if (count > 0) {
+				hdr_cnt = count;
+				hdr_ptr = hdr_buf;
+				_fcgi_make_header(&toFCGIhdr, FCGI_STDIN, hdr_cnt, 0);
+				toFCGIhdr_cnt = sizeof(toFCGIhdr);
+			} else {
+				/* no more POST data can be read */
+				post_len = 0;
+			}
+		}
+
+		if (pfd[1].revents & POLLOUT) {
+			/* Have data from peer and can write to CGI */
+			if (toFCGIhdr_cnt > 0) {
+				count = safe_write(sockfd, (unsigned char *)&toFCGIhdr + sizeof(toFCGIhdr) - toFCGIhdr_cnt, toFCGIhdr_cnt);
+				if (count > 0) {
+					toFCGIhdr_cnt -= count;
+
+					if (!toFCGIhdr_cnt && !post_len) {
+						shutdown(sockfd, SHUT_WR);
+					}
+				} else {
+					toFCGIhdr_cnt = hdr_cnt = post_len = 0;
+				}
+			}
+			if (!toFCGIhdr_cnt && hdr_cnt > 0) {
+				count = safe_write(sockfd, hdr_ptr, hdr_cnt);
+				if (count > 0) {
+					hdr_ptr += count;
+					hdr_cnt -= count;
+					post_len -= count;
+
+					/* terminate with an empty FCGI_STDIN message */
+					if (!hdr_cnt && !post_len) {
+						_fcgi_make_header(&toFCGIhdr, FCGI_STDIN, hdr_cnt, 0);
+						toFCGIhdr_cnt = sizeof(toFCGIhdr);
+					}
+				} else {
+					hdr_cnt = post_len = 0;
+				}
+			}
+		}
+
+		if (pfd[1].revents & POLLIN) {
+			/* There is something to read from CGI */
+
+			read_flag = 0;
+
+	 		if (fromFCGIhdr_cnt < sizeof(fromFCGIhdr)) {
+				count = safe_read(sockfd, (unsigned char *)&fromFCGIhdr + fromFCGIhdr_cnt,
sizeof(fromFCGIhdr) - fromFCGIhdr_cnt);
+				if (count <= 0)
+					goto exit_loop;
+
+				fromFCGIhdr_cnt += count;
+
+				/*
+				 * Header is complete (possibly from previous call).  What now?
+				 */
+				if (fromFCGIhdr_cnt < sizeof(fromFCGIhdr))
+					continue;
+
+				if (fromFCGIhdr.version != FCGI_VERSION_1)
+					exit(FCGX_UNSUPPORTED_VERSION);
+
+				if ((fromFCGIhdr.requestIdB1 << 8) + fromFCGIhdr.requestIdB0 != requestId)
+					exit(FCGX_PROTOCOL_ERROR);
+
+				clen = (fromFCGIhdr.contentLengthB1 << 8) + fromFCGIhdr.contentLengthB0;
+				plen = fromFCGIhdr.paddingLength;
+
+				switch(fromFCGIhdr.type) {
+				case FCGI_STDOUT:
+					if (out_cnt >= 0)
+						rbuf_cnt = out_cnt;
+					else
+						rbuf_cnt = 0;
+					rbuf = iobuf;
+					break;
+				case FCGI_END_REQUEST:
+					if(clen != sizeof(FCGI_EndRequestBody))
+						exit(FCGX_PROTOCOL_ERROR);
+				case FCGI_STDERR:
+				case FCGI_GET_VALUES_RESULT:
+				case FCGI_UNKNOWN_TYPE:
+					rbuf = iobuf + init_len;
+					rbuf_cnt = init_len;
+					break;
+				default:
+					exit(FCGX_PROTOCOL_ERROR);
+				}
+
+				read_flag = 1;
+			}
+
+			if (clen) {
+				count = safe_read(sockfd, rbuf + rbuf_cnt, clen + rbuf_cnt < PIPE_BUF ? clen : PIPE_BUF - rbuf_cnt);
+				if (count <= 0) {
+					if (read_flag)
+						continue;
+					goto exit_loop;
+				}
+
+				clen -= count;
+
+				switch(fromFCGIhdr.type) {
+				case FCGI_STDOUT:
+					/* Are we still buffering CGI output? */
+					if (out_cnt >= 0) {
+						out_cnt += count;
+						if (out_cnt < init_len) {
+							rbuf_cnt += count;
+							break;
+						}
+
+						count = out_cnt;
+						out_cnt = -1; /* buffering off */
+
+						/* "Status" header format is: "Status: 302 Redirected\r\n" */
+						if (!memcmp(rbuf, "Status: ", 8)) {
+							/* send "HTTP/1.0 " */
+							if (full_write(STDOUT_FILENO, HTTP_200, 9) != 9)
+								goto write_err;
+
+							/* skip "Status: " */
+							count -= 8;
+							if (full_write(STDOUT_FILENO, rbuf + 8, count) != count)
+								goto write_err;
+							break;
+						} else if (memcmp(rbuf, HTTP_200, 4)) {
+							/* there is no "HTTP", do it ourself */
+							if (full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1)
+								goto write_err;
+						}
+					}
+					if (full_write(STDOUT_FILENO, rbuf, count) != count)
+						goto write_err;
+
+					break;
+				case FCGI_STDERR:
+					full_write(STDERR_FILENO, rbuf, count);
+					break;
+				case FCGI_END_REQUEST:
+					break;
+				default:
+					break;
+				}
+
+				if (clen)
+					continue;
+
+				read_flag = 1;
+			}
+
+			if (plen) {
+				count = safe_read(sockfd, rbuf, plen < PIPE_BUF ? plen : PIPE_BUF);
+				if (count <= 0) {
+					if (read_flag)
+						continue;
+					goto exit_loop;
+				}
+
+				plen -= count;
+
+				if (plen)
+					continue;
+			}
+
+			fromFCGIhdr_cnt = 0;
+
+			if (fromFCGIhdr.type == FCGI_END_REQUEST) {
+#if 0
+				FCGI_EndRequestBody *erBody;
+
+				erBody = rbuf;
+				exitStatus = (erBody.appStatusB3 << 24)
+					   + (erBody.appStatusB2 << 16)
+					   + (erBody.appStatusB1 <<  8)
+					   + (erBody.appStatusB0);
+#endif
+				goto exit_loop;
+			}
+		}
+	}
+exit_loop:
+	/* eof (or error) and there was no "HTTP",
+	 * so write it, then write received data */
+	if (out_cnt > 0) {
+		if (out_cnt >=4 && memcmp(iobuf, HTTP_200, 4))
+			full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1);
+		full_write(STDOUT_FILENO, iobuf, out_cnt);
+	}
+write_err:
+	log_and_exit();
+}
+
+static int fcgi_connect(const char *addr)
+{
+	int sockfd;
+	len_and_sockaddr *r;
+
+	if (*addr == '/') {
+		struct sockaddr_un *sun;
+
+		r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
+		r->len = sizeof(struct sockaddr_un);
+		r->u.sa.sa_family = AF_UNIX;
+		sun = (struct sockaddr_un *)&r->u.sa;
+		safe_strncpy(sun->sun_path, addr, sizeof(sun->sun_path));
+	}
+	else {
+		r = xhost2sockaddr(addr, 9000);
+	}
+
+	sockfd = socket(r->u.sa.sa_family, SOCK_STREAM, 0);
+	if (sockfd != -1) {
+		if (connect(sockfd, &r->u.sa, r->len)) {
+			close(sockfd);
+			sockfd = -1;
+		}
+	}
+	return sockfd;
+}
+
+static void fcgi_exec(const char *server, int post_len) NORETURN;
+static void fcgi_exec(const char *server, int post_len)
+{
+	unsigned char *buf;
+	int nameLen, valueLen;
+	char **envp;
+	int sockfd;
+
+	sockfd = fcgi_connect(server);
+	if (sockfd < 0)
+		send_headers_and_exit(HTTP_NOT_FOUND);
+
+	buf = fcgi_make_header(FCGI_BEGIN_REQUEST, sizeof(FCGI_BeginRequestBody), 0);
+	buf = fcgi_begin_request(buf, FCGI_RESPONDER, FALSE);
+
+	if (full_write(sockfd, iobuf, buf - (unsigned char *)iobuf) != buf - (unsigned char *)iobuf)
+		log_and_exit();
+
+	/*
+	 * Send environment to the FCGI application server
+	 */
+	buf = fcgi_make_header(FCGI_PARAMS, 0, 0);
+
+	for(envp = environ ; *envp; envp++) {
+		char *p = strchr(*envp, '=');
+
+		if (!p) {
+			nameLen = strlen(*envp);
+			valueLen = 0;
+		}
+		else {
+			nameLen = p - *envp;
+			valueLen = strlen(p + 1);
+		}
+		buf = fcgi_set_param(sockfd, buf, *envp, nameLen, valueLen);
+	}
+
+	if (buf != (unsigned char *)iobuf + sizeof(FCGI_Header))
+		buf = fcgi_flush_param(sockfd, buf);
+
+	fcgi_flush_param(sockfd, buf);
+	fcgi_io_loop_and_exit(sockfd, post_len);
+}
+#endif
+
 #if ENABLE_FEATURE_HTTPD_CGI

 static void setenv1(const char *name, const char *value)
 <at>  <at>  -1303,6 +1827,9  <at>  <at>  static void send_cgi_and_exit(
 	struct fd_pair toCgi;    /* httpd -> CGI pipe */
 	char *script, *last_slash;
 	int pid;
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	Htaccess *interpr = NULL;
+#endif

 	/* Make a copy. NB: caller guarantees:
 	 * url[0] == '/', url[1] != '/' */
 <at>  <at>  -1395,9 +1922,34  <at>  <at>  static void send_cgi_and_exit(
 	if (referer)
 		setenv1("HTTP_REFERER", referer);
 	setenv1("HTTP_HOST", host); /* set to "" if NULL */
-	/* setenv1("SERVER_NAME", safe_gethostname()); - don't do this,
-	 * just run "env SERVER_NAME=xyz httpd ..." instead */

+
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	{
+		char *suffix = strrchr(last_slash + 1, '.');
+
+		if (suffix) {
+			for (interpr = script_i; interpr; interpr = interpr->next) {
+				if (strcmp(interpr->before_colon + 1, suffix) == 0) {
+					/* found interpreter name */
+					break;
+				}
+			}
+		}
+	}
+
+#if ENABLE_FEATURE_HTTPD_FAST_CGI
+	if (interpr && *interpr->after_colon == ' <at> ') {
+		if (!getenv("SERVER_NAME"))
+			setenv1("SERVER_NAME", safe_gethostname());
+
+		if (!getenv("SERVER_ADDR"))
+			setenv1("SERVER_ADDR", "127.0.0.1");
+
+		fcgi_exec(interpr->after_colon + 1, post_len);
+	}
+#endif
+#endif
 	xpiped_pair(fromCgi);
 	xpiped_pair(toCgi);

 <at>  <at>  -1434,26 +1986,17  <at>  <at>  static void send_cgi_and_exit(
 		}
 		script++;

-		/* set argv[0] to name without path */
-		argv[0] = script;
-		argv[1] = NULL;
-
 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+		if (interpr) {
+			argv[0] = interpr->after_colon;
+			argv[1] = script;
+			argv[2] = NULL;
+		} else
+#else
 		{
-			char *suffix = strrchr(script, '.');
-
-			if (suffix) {
-				Htaccess *cur;
-				for (cur = script_i; cur; cur = cur->next) {
-					if (strcmp(cur->before_colon + 1, suffix) == 0) {
-						/* found interpreter name */
-						argv[0] = cur->after_colon;
-						argv[1] = script;
-						argv[2] = NULL;
-						break;
-					}
-				}
-			}
+			/* set argv[0] to name without path */
+			argv[0] = script;
+			argv[1] = NULL;
 		}
 #endif
 		/* restore default signal dispositions for CGI process */
diff -u -N -r -p busybox-1.22.1.orig/networking/Config.src busybox-1.22.1/networking/Config.src
--- busybox-1.22.1.orig/networking/Config.src	2014-01-09 19:15:44.000000000 +0100
+++ busybox-1.22.1/networking/Config.src	2014-07-04 09:36:00.849170052 +0200
 <at>  <at>  -224,6 +224,14  <at>  <at>  config FEATURE_HTTPD_CGI
 	  This option allows scripts and executables to be invoked
 	  when specific URLs are requested.

+config FEATURE_HTTPD_FAST_CGI
+	bool "Enabel fast CGI Support"
+	default y
+	depends on FEATURE_HTTPD_CGI
+	select FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	help
+	  This option enables support for fast cgi
+
 config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
 	bool "Support for running scripts through an interpreter"
 	default y
Stefani Seibold | 7 Jul 14:35 2014
Picon

Fast CGI for busybox

Hi,

this patch add Fast CGI Support to the busybox httpd web server. I hope you like it ;-)

To connect a extension to a fast CGI socket add a
*.<extension>: <at> <path to fcgi socket>
to the httpd.conf

Greetings,
Stefani

diff -u -N -r -p busybox-1.22.1.orig/networking/httpd.c busybox-1.22.1/networking/httpd.c
--- busybox-1.22.1/networking/httpd.c	2014-01-09 19:15:44.000000000 +0100
+++ busybox-1.22.1/networking/httpd.c	2014-07-04 09:37:56.128167910 +0200
 <at>  <at>  -136,6 +136,10  <at>  <at> 
 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
 # include <sys/sendfile.h>
 #endif
+#if ENABLE_FEATURE_HTTPD_FAST_CGI
+# include <sys/un.h>
+#endif
+
 /* amount of buffering in a pipe */
 #ifndef PIPE_BUF
 # define PIPE_BUF 4096
 <at>  <at>  -955,10 +959,16  <at>  <at>  static void send_headers(int responseNum
 	/* emit the current date */
 	strftime(tmp_str, sizeof(tmp_str), RFC1123FMT, gmtime(&timer));
 	len = sprintf(iobuf,
-			"HTTP/1.0 %d %s\r\nContent-type: %s\r\n"
-			"Date: %s\r\nConnection: close\r\n",
-			responseNum, responseString, mime_type, tmp_str);
+			"HTTP/1.0 %d %s\r\n"
+			"Date: %s\r\n"
+			"Connection: close\r\n"
+			"Content-Type: %s",
+			responseNum, responseString, tmp_str, mime_type);

+	if (infoString) {
+			len += sprintf(iobuf + len, "; charset=iso-8859-1");
+	}
+	len += sprintf(iobuf + len, "\r\n");
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
 	if (responseNum == HTTP_UNAUTHORIZED) {
 		len += sprintf(iobuf + len,
 <at>  <at>  -1009,7 +1019,7  <at>  <at>  static void send_headers(int responseNum
 		);
 	}

-	if (content_gzip)
+	if (content_gzip && !infoString)
 		len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n");

 	iobuf[len++] = '\r';
 <at>  <at>  -1263,6 +1273,520  <at>  <at>  static NOINLINE void cgi_io_loop_and_exi
 }
 #endif

+#if ENABLE_FEATURE_HTTPD_FAST_CGI
+
+/*
+ * Error codes.  Assigned to avoid conflict with EOF and errno(2).
+ */
+#define FCGX_UNSUPPORTED_VERSION -2
+#define FCGX_PROTOCOL_ERROR -3
+
+typedef struct {
+	unsigned char version;
+	unsigned char type;
+	unsigned char requestIdB1;
+	unsigned char requestIdB0;
+	unsigned char contentLengthB1;
+	unsigned char contentLengthB0;
+	unsigned char paddingLength;
+	unsigned char reserved;
+} FCGI_Header;
+
+/*
+ * Number of bytes in a FCGI_Header.  Future versions of the protocol
+ * will not reduce this number.
+ */
+#define FCGI_HEADER_LEN		8
+
+/*
+ * Value for version component of FCGI_Header
+ */
+#define FCGI_VERSION_1		1
+
+/*
+ * Values for type component of FCGI_Header
+ */
+#define FCGI_BEGIN_REQUEST	1
+#define FCGI_ABORT_REQUEST	2
+#define FCGI_END_REQUEST	3
+#define FCGI_PARAMS		4
+#define FCGI_STDIN		5
+#define FCGI_STDOUT		6
+#define FCGI_STDERR		7
+#define FCGI_DATA		8
+#define FCGI_GET_VALUES		9
+#define FCGI_GET_VALUES_RESULT  10
+#define FCGI_UNKNOWN_TYPE	11
+#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
+
+/*
+ * Value for requestId component of FCGI_Header
+ */
+#define FCGI_NULL_REQUEST_ID	0
+
+typedef struct {
+	unsigned char roleB1;
+	unsigned char roleB0;
+	unsigned char flags;
+	unsigned char reserved[5];
+} FCGI_BeginRequestBody;
+
+/*
+ * Mask for flags component of FCGI_BeginRequestBody
+ */
+#define FCGI_KEEP_CONN		1
+
+/*
+ * Values for role component of FCGI_BeginRequestBody
+ */
+#define FCGI_RESPONDER		1
+#define FCGI_AUTHORIZER		2
+#define FCGI_FILTER		3
+
+typedef struct {
+	unsigned char appStatusB3;
+	unsigned char appStatusB2;
+	unsigned char appStatusB1;
+	unsigned char appStatusB0;
+	unsigned char protocolStatus;
+	unsigned char reserved[3];
+} FCGI_EndRequestBody;
+
+/*
+ * Values for protocolStatus component of FCGI_EndRequestBody
+ */
+#define FCGI_REQUEST_COMPLETE	0
+#define FCGI_CANT_MPX_CONN	1
+#define FCGI_OVERLOADED		2
+#define FCGI_UNKNOWN_ROLE	3
+
+/*
+ * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records
+ */
+#define FCGI_MAX_CONNS  "FCGI_MAX_CONNS"
+#define FCGI_MAX_REQS   "FCGI_MAX_REQS"
+#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"
+
+static const unsigned short requestId = 1;
+
+static void * fcgi_flush_param(int sockfd, unsigned char *buf)
+{
+	FCGI_Header *header = (FCGI_Header *)iobuf;
+	unsigned short clen = buf - (unsigned char *)iobuf - sizeof(*header);
+	unsigned int len = (clen + 7) & ~7;
+
+	header->contentLengthB1 = clen >> 8;
+	header->contentLengthB0 = clen;
+	header->paddingLength = len - clen;
+
+	memset(buf, 0, len - clen);
+
+	len += sizeof(*header);
+
+	if (full_write(sockfd, iobuf, len) != len)
+		log_and_exit();
+
+	return iobuf + sizeof(*header);
+}
+
+static void * fcgi_store(int sockfd, unsigned char *buf, unsigned char v)
+{
+	if (buf - (unsigned char *)iobuf >= IOBUF_SIZE)
+		buf = fcgi_flush_param(sockfd, buf);
+	
+	*buf++ = v;
+
+	return buf;
+}
+
+static void * fcgi_store_len(int sockfd, unsigned char *buf, unsigned int len)
+{
+	if (len < 0x80) {
+		buf = fcgi_store(sockfd, buf, len);
+	} else {
+		buf = fcgi_store(sockfd, buf, (len >> 24) | 0x80);
+		buf = fcgi_store(sockfd, buf, len >> 16);
+		buf = fcgi_store(sockfd, buf, len >> 8);
+		buf = fcgi_store(sockfd, buf, len);
+	}
+	return buf;
+}
+
+static void * fcgi_set_param(int sockfd, unsigned char *buf, char *env, unsigned int nameLen, unsigned
int valueLen)
+{
+	buf = fcgi_store_len(sockfd, buf, nameLen);
+	buf = fcgi_store_len(sockfd, buf, valueLen);
+
+	while(nameLen--)
+		buf = fcgi_store(sockfd, buf, *env++);
+	env++;
+	while(valueLen--)
+		buf = fcgi_store(sockfd, buf, *env++);
+
+	return buf;
+}
+
+static void * fcgi_begin_request(void *buf, unsigned short role, int keepConnection)
+{
+	FCGI_BeginRequestBody *body = buf;
+
+	body->roleB1 = role >> 8;
+	body->roleB0 = role;
+	body->flags  = keepConnection ? FCGI_KEEP_CONN : 0;
+	memset(&body->reserved, 0, sizeof(body->reserved));
+
+	return buf + sizeof(*body);
+}
+
+static void _fcgi_make_header(FCGI_Header *header, unsigned char type, unsigned short
contentLength, unsigned char paddingLength)
+{
+	header->version = FCGI_VERSION_1;
+	header->type = type;
+	header->requestIdB1 = requestId >> 8;
+	header->requestIdB0 = requestId;
+	header->contentLengthB1 = contentLength >> 8;
+	header->contentLengthB0 = contentLength;
+	header->paddingLength = paddingLength;
+	header->reserved =  0;
+}
+
+static void * fcgi_make_header(unsigned char type, unsigned short contentLength, unsigned char paddingLength)
+{
+	FCGI_Header *header = (FCGI_Header *)iobuf;
+
+	_fcgi_make_header(header, type, contentLength, paddingLength);
+
+	return iobuf + sizeof(*header);
+}
+
+/* gcc 4.2.1 fares better with NOINLINE */
+static NOINLINE void fcgi_io_loop_and_exit(int sockfd, int post_len) NORETURN;
+static NOINLINE void fcgi_io_loop_and_exit(int sockfd, int post_len)
+{
+	struct pollfd pfd[2];
+	int out_cnt; /* we buffer a bit of initial CGI output */
+	const int init_len = 8;
+	unsigned int rbuf_cnt;
+	int count;
+	FCGI_Header toFCGIhdr, fromFCGIhdr;
+	unsigned int toFCGIhdr_cnt, fromFCGIhdr_cnt;
+	unsigned int clen, plen;
+	char *rbuf = NULL;
+	int read_flag;
+
+	_fcgi_make_header(&toFCGIhdr, FCGI_STDIN, hdr_cnt, 0);
+	toFCGIhdr_cnt = sizeof(toFCGIhdr);
+	fromFCGIhdr_cnt = 0;
+	clen = 0;
+	plen = 0;
+
+	/* iobuf is used for CGI -> network data,
+	 * hdr_buf is for network -> CGI data (POSTDATA) */
+
+	/* If CGI dies, we still want to correctly finish reading its output
+	 * and send it to the peer. So please no SIGPIPEs! */
+	signal(SIGPIPE, SIG_IGN);
+
+	// We inconsistently handle a case when more POSTDATA from network
+	// is coming than we expected. We may give *some part* of that
+	// extra data to CGI.
+
+	/* NB: breaking out of this loop jumps to log_and_exit() */
+	out_cnt = 0;
+	rbuf_cnt = 0;
+
+	while (1) {
+		memset(pfd, 0, sizeof(pfd));
+
+		pfd[1].fd = sockfd;
+		pfd[1].events = POLLIN;
+
+		if (toFCGIhdr_cnt || hdr_cnt)  {
+			pfd[1].events |= POLLOUT;
+		} else {
+			if (post_len > 0)
+				pfd[0].events = POLLIN;
+		}
+
+		/* Now wait on the set of sockets */
+		count = safe_poll(pfd, 2, -1);
+		if (count <= 0)
+			break;
+
+		if (pfd[0].revents) {
+			/* post_len > 0 && hdr_cnt == 0 here */
+			/* We expect data, prev data portion is eaten by CGI
+			 * and there *is* data to read from the peer
+			 * (POSTDATA) */
+			count = safe_read(STDIN_FILENO, hdr_buf, sizeof(hdr_buf));
+			if (count > 0) {
+				hdr_cnt = count;
+				hdr_ptr = hdr_buf;
+				_fcgi_make_header(&toFCGIhdr, FCGI_STDIN, hdr_cnt, 0);
+				toFCGIhdr_cnt = sizeof(toFCGIhdr);
+			} else {
+				/* no more POST data can be read */
+				post_len = 0;
+			}
+		}
+
+		if (pfd[1].revents & POLLOUT) {
+			/* Have data from peer and can write to CGI */
+			if (toFCGIhdr_cnt > 0) {
+				count = safe_write(sockfd, (unsigned char *)&toFCGIhdr + sizeof(toFCGIhdr) - toFCGIhdr_cnt, toFCGIhdr_cnt);
+				if (count > 0) {
+					toFCGIhdr_cnt -= count;
+
+					if (!toFCGIhdr_cnt && !post_len) {
+						shutdown(sockfd, SHUT_WR);
+					}
+				} else {
+					toFCGIhdr_cnt = hdr_cnt = post_len = 0;
+				}
+			}
+			if (!toFCGIhdr_cnt && hdr_cnt > 0) {
+				count = safe_write(sockfd, hdr_ptr, hdr_cnt);
+				if (count > 0) {
+					hdr_ptr += count;
+					hdr_cnt -= count;
+					post_len -= count;
+
+					/* terminate with an empty FCGI_STDIN message */
+					if (!hdr_cnt && !post_len) {
+						_fcgi_make_header(&toFCGIhdr, FCGI_STDIN, hdr_cnt, 0);
+						toFCGIhdr_cnt = sizeof(toFCGIhdr);
+					}
+				} else {
+					hdr_cnt = post_len = 0;
+				}
+			}
+		}
+
+		if (pfd[1].revents & POLLIN) {
+			/* There is something to read from CGI */
+
+			read_flag = 0;
+
+	 		if (fromFCGIhdr_cnt < sizeof(fromFCGIhdr)) {
+				count = safe_read(sockfd, (unsigned char *)&fromFCGIhdr + fromFCGIhdr_cnt,
sizeof(fromFCGIhdr) - fromFCGIhdr_cnt);
+				if (count <= 0)
+					goto exit_loop;
+
+				fromFCGIhdr_cnt += count;
+
+				/*
+				 * Header is complete (possibly from previous call).  What now?
+				 */
+				if (fromFCGIhdr_cnt < sizeof(fromFCGIhdr))
+					continue;
+
+				if (fromFCGIhdr.version != FCGI_VERSION_1)
+					exit(FCGX_UNSUPPORTED_VERSION);
+
+				if ((fromFCGIhdr.requestIdB1 << 8) + fromFCGIhdr.requestIdB0 != requestId)
+					exit(FCGX_PROTOCOL_ERROR);
+
+				clen = (fromFCGIhdr.contentLengthB1 << 8) + fromFCGIhdr.contentLengthB0;
+				plen = fromFCGIhdr.paddingLength;
+
+				switch(fromFCGIhdr.type) {
+				case FCGI_STDOUT:
+					if (out_cnt >= 0)
+						rbuf_cnt = out_cnt;
+					else
+						rbuf_cnt = 0;
+					rbuf = iobuf;
+					break;
+				case FCGI_END_REQUEST:
+					if(clen != sizeof(FCGI_EndRequestBody))
+						exit(FCGX_PROTOCOL_ERROR);
+				case FCGI_STDERR:
+				case FCGI_GET_VALUES_RESULT:
+				case FCGI_UNKNOWN_TYPE:
+					rbuf = iobuf + init_len;
+					rbuf_cnt = init_len;
+					break;
+				default:
+					exit(FCGX_PROTOCOL_ERROR);
+				}
+
+				read_flag = 1;
+			}
+
+			if (clen) {
+				count = safe_read(sockfd, rbuf + rbuf_cnt, clen + rbuf_cnt < PIPE_BUF ? clen : PIPE_BUF - rbuf_cnt);
+				if (count <= 0) {
+					if (read_flag)
+						continue;
+					goto exit_loop;
+				}
+
+				clen -= count;
+
+				switch(fromFCGIhdr.type) {
+				case FCGI_STDOUT:
+					/* Are we still buffering CGI output? */
+					if (out_cnt >= 0) {
+						out_cnt += count;
+						if (out_cnt < init_len) {
+							rbuf_cnt += count;
+							break;
+						}
+
+						count = out_cnt;
+						out_cnt = -1; /* buffering off */
+
+						/* "Status" header format is: "Status: 302 Redirected\r\n" */
+						if (!memcmp(rbuf, "Status: ", 8)) {
+							/* send "HTTP/1.0 " */
+							if (full_write(STDOUT_FILENO, HTTP_200, 9) != 9)
+								goto write_err;
+
+							/* skip "Status: " */
+							count -= 8;
+							if (full_write(STDOUT_FILENO, rbuf + 8, count) != count)
+								goto write_err;
+							break;
+						} else if (memcmp(rbuf, HTTP_200, 4)) {
+							/* there is no "HTTP", do it ourself */
+							if (full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1) != sizeof(HTTP_200)-1)
+								goto write_err;
+						}
+					}
+					if (full_write(STDOUT_FILENO, rbuf, count) != count)
+						goto write_err;
+
+					break;
+				case FCGI_STDERR:
+					full_write(STDERR_FILENO, rbuf, count);
+					break;
+				case FCGI_END_REQUEST:
+					break;
+				default:
+					break;
+				}
+
+				if (clen)
+					continue;
+
+				read_flag = 1;
+			}
+
+			if (plen) {
+				count = safe_read(sockfd, rbuf, plen < PIPE_BUF ? plen : PIPE_BUF);
+				if (count <= 0) {
+					if (read_flag)
+						continue;
+					goto exit_loop;
+				}
+
+				plen -= count;
+
+				if (plen)
+					continue;
+			}
+
+			fromFCGIhdr_cnt = 0;
+
+			if (fromFCGIhdr.type == FCGI_END_REQUEST) {
+#if 0
+				FCGI_EndRequestBody *erBody;
+
+				erBody = rbuf;
+				exitStatus = (erBody.appStatusB3 << 24)
+					   + (erBody.appStatusB2 << 16)
+					   + (erBody.appStatusB1 <<  8)
+					   + (erBody.appStatusB0);
+#endif
+				goto exit_loop;
+			}
+		}
+	}
+exit_loop:
+	/* eof (or error) and there was no "HTTP",
+	 * so write it, then write received data */
+	if (out_cnt > 0) {
+		if (out_cnt >=4 && memcmp(iobuf, HTTP_200, 4))
+			full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1);
+		full_write(STDOUT_FILENO, iobuf, out_cnt);
+	}
+write_err:
+	log_and_exit();
+}
+
+static int fcgi_connect(const char *addr)
+{
+	int sockfd;
+	len_and_sockaddr *r;
+
+	if (*addr == '/') {
+		struct sockaddr_un *sun;
+
+		r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
+		r->len = sizeof(struct sockaddr_un);
+		r->u.sa.sa_family = AF_UNIX;
+		sun = (struct sockaddr_un *)&r->u.sa;
+		safe_strncpy(sun->sun_path, addr, sizeof(sun->sun_path));
+	}
+	else {
+		r = xhost2sockaddr(addr, 9000);
+	}
+
+	sockfd = socket(r->u.sa.sa_family, SOCK_STREAM, 0);
+	if (sockfd != -1) {
+		if (connect(sockfd, &r->u.sa, r->len)) {
+			close(sockfd);
+			sockfd = -1;
+		}
+	}
+	return sockfd;
+}
+
+static void fcgi_exec(const char *server, int post_len) NORETURN;
+static void fcgi_exec(const char *server, int post_len)
+{
+	unsigned char *buf;
+	int nameLen, valueLen;
+	char **envp;
+	int sockfd;
+
+	sockfd = fcgi_connect(server);
+	if (sockfd < 0)
+		send_headers_and_exit(HTTP_NOT_FOUND);
+
+	buf = fcgi_make_header(FCGI_BEGIN_REQUEST, sizeof(FCGI_BeginRequestBody), 0);
+	buf = fcgi_begin_request(buf, FCGI_RESPONDER, FALSE);
+
+	if (full_write(sockfd, iobuf, buf - (unsigned char *)iobuf) != buf - (unsigned char *)iobuf)
+		log_and_exit();
+
+	/*
+	 * Send environment to the FCGI application server
+	 */
+	buf = fcgi_make_header(FCGI_PARAMS, 0, 0);
+
+	for(envp = environ ; *envp; envp++) {
+		char *p = strchr(*envp, '=');
+
+		if (!p) {
+			nameLen = strlen(*envp);
+			valueLen = 0;
+		}
+		else {
+			nameLen = p - *envp;
+			valueLen = strlen(p + 1);
+		}
+		buf = fcgi_set_param(sockfd, buf, *envp, nameLen, valueLen);
+	}
+
+	if (buf != (unsigned char *)iobuf + sizeof(FCGI_Header))
+		buf = fcgi_flush_param(sockfd, buf);
+
+	fcgi_flush_param(sockfd, buf);
+	fcgi_io_loop_and_exit(sockfd, post_len);
+}
+#endif
+
 #if ENABLE_FEATURE_HTTPD_CGI

 static void setenv1(const char *name, const char *value)
 <at>  <at>  -1303,6 +1827,9  <at>  <at>  static void send_cgi_and_exit(
 	struct fd_pair toCgi;    /* httpd -> CGI pipe */
 	char *script, *last_slash;
 	int pid;
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	Htaccess *interpr = NULL;
+#endif

 	/* Make a copy. NB: caller guarantees:
 	 * url[0] == '/', url[1] != '/' */
 <at>  <at>  -1395,9 +1922,34  <at>  <at>  static void send_cgi_and_exit(
 	if (referer)
 		setenv1("HTTP_REFERER", referer);
 	setenv1("HTTP_HOST", host); /* set to "" if NULL */
-	/* setenv1("SERVER_NAME", safe_gethostname()); - don't do this,
-	 * just run "env SERVER_NAME=xyz httpd ..." instead */

+
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	{
+		char *suffix = strrchr(last_slash + 1, '.');
+
+		if (suffix) {
+			for (interpr = script_i; interpr; interpr = interpr->next) {
+				if (strcmp(interpr->before_colon + 1, suffix) == 0) {
+					/* found interpreter name */
+					break;
+				}
+			}
+		}
+	}
+
+#if ENABLE_FEATURE_HTTPD_FAST_CGI
+	if (interpr && *interpr->after_colon == ' <at> ') {
+		if (!getenv("SERVER_NAME"))
+			setenv1("SERVER_NAME", safe_gethostname());
+
+		if (!getenv("SERVER_ADDR"))
+			setenv1("SERVER_ADDR", "127.0.0.1");
+
+		fcgi_exec(interpr->after_colon + 1, post_len);
+	}
+#endif
+#endif
 	xpiped_pair(fromCgi);
 	xpiped_pair(toCgi);

 <at>  <at>  -1434,26 +1986,17  <at>  <at>  static void send_cgi_and_exit(
 		}
 		script++;

-		/* set argv[0] to name without path */
-		argv[0] = script;
-		argv[1] = NULL;
-
 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+		if (interpr) {
+			argv[0] = interpr->after_colon;
+			argv[1] = script;
+			argv[2] = NULL;
+		} else
+#else
 		{
-			char *suffix = strrchr(script, '.');
-
-			if (suffix) {
-				Htaccess *cur;
-				for (cur = script_i; cur; cur = cur->next) {
-					if (strcmp(cur->before_colon + 1, suffix) == 0) {
-						/* found interpreter name */
-						argv[0] = cur->after_colon;
-						argv[1] = script;
-						argv[2] = NULL;
-						break;
-					}
-				}
-			}
+			/* set argv[0] to name without path */
+			argv[0] = script;
+			argv[1] = NULL;
 		}
 #endif
 		/* restore default signal dispositions for CGI process */
diff -u -N -r -p busybox-1.22.1.orig/networking/Config.src busybox-1.22.1/networking/Config.src
--- busybox-1.22.1.orig/networking/Config.src	2014-01-09 19:15:44.000000000 +0100
+++ busybox-1.22.1/networking/Config.src	2014-07-04 09:36:00.849170052 +0200
 <at>  <at>  -224,6 +224,14  <at>  <at>  config FEATURE_HTTPD_CGI
 	  This option allows scripts and executables to be invoked
 	  when specific URLs are requested.

+config FEATURE_HTTPD_FAST_CGI
+	bool "Enabel fast CGI Support"
+	default y
+	depends on FEATURE_HTTPD_CGI
+	select FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+	help
+	  This option enables support for fast cgi
+
 config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
 	bool "Support for running scripts through an interpreter"
 	default y
Sunil Saraff | 7 Jul 13:00 2014
Picon

Query regarding libbb

Hi,

I am using busybox 1.20.2. In libbb, file lineedit.c, macro ENABLE_FEATURE_EDITING_ASK_TERMINAL is used. I did not understand the use of this functionality. With this feature enabled, just after the shell prompt "]6n" characters are sent. If i disable this feature, what could be the impact?

Thanks,
Sunil


_______________________________________________
busybox mailing list
busybox <at> busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Gmane