Example #1
0
DECLARE_TEST(tcp, blocking) {
	socket_t* sock = tcp_socket_allocate();

	socket_set_blocking(sock, false);
	EXPECT_FALSE(socket_blocking(sock));

	socket_set_blocking(sock, true);
	EXPECT_TRUE(socket_blocking(sock));

	socket_deallocate(sock);

	return 0;
}
Example #2
0
File: reqs.c Project: OPSF/uClinux
/*
 * pull_client_data is used to pull across any client data (like in a
 * POST) which needs to be handled before an error can be reported, or
 * server headers can be processed.
 *	- rjkaes
 */
static int
pull_client_data(struct conn_s *connptr, long int length)
{
	char *buffer;
	ssize_t len;

	buffer = safemalloc(min(MAXBUFFSIZE, length));
	if (!buffer)
		return -1;

	do {
		len = safe_read(connptr->client_fd, buffer,
				min(MAXBUFFSIZE, length));
		if (len <= 0)
			goto ERROR_EXIT;

		if (!connptr->error_variables) {
			if (safe_write(connptr->server_fd, buffer, len) < 0)
				goto ERROR_EXIT;
		}

		length -= len;
	} while (length > 0);

	/*
	 * BUG FIX: Internet Explorer will leave two bytes (carriage
	 * return and line feed) at the end of a POST message.  These
	 * need to be eaten for tinyproxy to work correctly.
	 */
	socket_nonblocking(connptr->client_fd);
	len = recv(connptr->client_fd, buffer, 2, MSG_PEEK);
	socket_blocking(connptr->client_fd);

	if (len < 0 && errno != EAGAIN)
		goto ERROR_EXIT;

	if (len == 2 && CHECK_CRLF(buffer, len))
		read(connptr->client_fd, buffer, 2);

	safefree(buffer);
	return 0;

  ERROR_EXIT:
	safefree(buffer);
	return -1;
}
Example #3
0
File: reqs.c Project: OPSF/uClinux
/*
 * Switch the sockets into nonblocking mode and begin relaying the bytes
 * between the two connections. We continue to use the buffering code
 * since we want to be able to buffer a certain amount for slower
 * connections (as this was the reason why I originally modified
 * tinyproxy oh so long ago...)
 *	- rjkaes
 */
static void
relay_connection(struct conn_s *connptr)
{
	fd_set rset, wset;
	struct timeval tv;
	time_t last_access;
	int ret;
	double tdiff;
	int maxfd = max(connptr->client_fd, connptr->server_fd) + 1;
	ssize_t bytes_received;

	socket_nonblocking(connptr->client_fd);
	socket_nonblocking(connptr->server_fd);

	last_access = time(NULL);

	for (;;) {
		FD_ZERO(&rset);
		FD_ZERO(&wset);

		tv.tv_sec =
		    config.idletimeout - difftime(time(NULL), last_access);
		tv.tv_usec = 0;

		if (buffer_size(connptr->sbuffer) > 0)
			FD_SET(connptr->client_fd, &wset);
		if (buffer_size(connptr->cbuffer) > 0)
			FD_SET(connptr->server_fd, &wset);
		if (buffer_size(connptr->sbuffer) < MAXBUFFSIZE)
			FD_SET(connptr->server_fd, &rset);
		if (buffer_size(connptr->cbuffer) < MAXBUFFSIZE)
			FD_SET(connptr->client_fd, &rset);

		ret = select(maxfd, &rset, &wset, NULL, &tv);

		if (ret == 0) {
			tdiff = difftime(time(NULL), last_access);
			if (tdiff > config.idletimeout) {
				log_message(LOG_INFO,
					    "Idle Timeout (after select) as %g > %u.",
					    tdiff, config.idletimeout);
				return;
			} else {
				continue;
			}
		} else if (ret < 0) {
			log_message(LOG_ERR,
				    "relay_connection: select() error \"%s\". Closing connection (client_fd:%d, server_fd:%d)",
				    strerror(errno), connptr->client_fd,
				    connptr->server_fd);
			return;
		} else {
			/*
			 * All right, something was actually selected so mark it.
			 */
			last_access = time(NULL);
		}

		if (FD_ISSET(connptr->server_fd, &rset)) {
			bytes_received = read_buffer(connptr->server_fd, connptr->sbuffer);
			if (bytes_received < 0)
				break;

			connptr->content_length.server -= bytes_received;
			if (connptr->content_length.server == 0)
				break;
		}
		if (FD_ISSET(connptr->client_fd, &rset)
		    && read_buffer(connptr->client_fd, connptr->cbuffer) < 0) {
			break;
		}
		if (FD_ISSET(connptr->server_fd, &wset)
		    && write_buffer(connptr->server_fd, connptr->cbuffer) < 0) {
			break;
		}
		if (FD_ISSET(connptr->client_fd, &wset)
		    && write_buffer(connptr->client_fd, connptr->sbuffer) < 0) {
			break;
		}
	}

	/*
	 * Here the server has closed the connection... write the
	 * remainder to the client and then exit.
	 */
	socket_blocking(connptr->client_fd);
	while (buffer_size(connptr->sbuffer) > 0) {
		if (write_buffer(connptr->client_fd, connptr->sbuffer) < 0)
			break;
	}
	shutdown(connptr->client_fd, SHUT_WR);

	/*
	 * Try to send any remaining data to the server if we can.
	 */
	socket_blocking(connptr->server_fd);
	while (buffer_size(connptr->cbuffer) > 0) {
		if (write_buffer(connptr->server_fd, connptr->cbuffer) < 0)
			break;
	}

	return;
}
Example #4
0
/*
 * This is the main (per child) loop.
 */
static void child_main (struct child_s *ptr)
{
    int connfd;
    struct sockaddr *cliaddr;
    socklen_t clilen;
    fd_set rfds;
    int maxfd = 0;
    ssize_t i;
    int ret;

    cliaddr = (struct sockaddr *)
              safemalloc (sizeof(struct sockaddr_storage));
    if (!cliaddr) {
        log_message (LOG_CRIT,
                     "Could not allocate memory for child address.");
        exit (0);
    }

    ptr->connects = 0;

    /*
     * We have to wait for connections on multiple fds,
     * so use select.
     */

    FD_ZERO(&rfds);

    for (i = 0; i < vector_length(listen_fds); i++) {
        int *fd = (int *) vector_getentry(listen_fds, i, NULL);

        ret = socket_nonblocking(*fd);
        if (ret != 0) {
            log_message(LOG_ERR, "Failed to set the listening "
                        "socket %d to non-blocking: %s",
                        fd, strerror(errno));
            exit(1);
        }

        FD_SET(*fd, &rfds);
        maxfd = max(maxfd, *fd);
    }

    while (!config.quit) {
        int listenfd = -1;

        ptr->status = T_WAITING;

        clilen = sizeof(struct sockaddr_storage);

        ret = select(maxfd + 1, &rfds, NULL, NULL, NULL);
        if (ret == -1) {
            log_message (LOG_ERR, "error calling select: %s",
                         strerror(errno));
            exit(1);
        } else if (ret == 0) {
            log_message (LOG_WARNING, "Strange: select returned 0 "
                         "but we did not specify a timeout...");
            continue;
        }

        for (i = 0; i < vector_length(listen_fds); i++) {
            int *fd = (int *) vector_getentry(listen_fds, i, NULL);

            if (FD_ISSET(*fd, &rfds)) {
                /*
                 * only accept the connection on the first
                 * fd that we find readable. - fair?
                 */
                listenfd = *fd;
                break;
            }
        }

        if (listenfd == -1) {
            log_message(LOG_WARNING, "Strange: None of our listen "
                        "fds was readable after select");
            continue;
        }

        ret = socket_blocking(listenfd);
        if (ret != 0) {
            log_message(LOG_ERR, "Failed to set listening "
                        "socket %d to blocking for accept: %s",
                        listenfd, strerror(errno));
            exit(1);
        }

        /*
         * We have a socket that is readable.
         * Continue handling this connection.
         */

        connfd = accept (listenfd, cliaddr, &clilen);

#ifndef NDEBUG
        /*
         * Enable the TINYPROXY_DEBUG environment variable if you
         * want to use the GDB debugger.
         */
        if (getenv ("TINYPROXY_DEBUG")) {
            /* Pause for 10 seconds to allow us to connect debugger */
            fprintf (stderr,
                     "Process has accepted connection: %ld\n",
                     (long int) ptr->tid);
            sleep (10);
            fprintf (stderr, "Continuing process: %ld\n",
                     (long int) ptr->tid);
        }
#endif

        /*
         * Make sure no error occurred...
         */
        if (connfd < 0) {
            log_message (LOG_ERR,
                         "Accept returned an error (%s) ... retrying.",
                         strerror (errno));
            continue;
        }

        ptr->status = T_CONNECTED;

        SERVER_DEC ();

        handle_connection (connfd);
        ptr->connects++;

        if (child_config.maxrequestsperchild != 0) {
            DEBUG2 ("%u connections so far...", ptr->connects);

            if (ptr->connects == child_config.maxrequestsperchild) {
                log_message (LOG_NOTICE,
                             "Child has reached MaxRequestsPerChild (%u). "
                             "Killing child.", ptr->connects);
                break;
            }
        }

        SERVER_COUNT_LOCK ();
        if (*servers_waiting > child_config.maxspareservers) {
            /*
             * There are too many spare children, kill ourself
             * off.
             */
            log_message (LOG_NOTICE,
                         "Waiting servers (%d) exceeds MaxSpareServers (%d). "
                         "Killing child.",
                         *servers_waiting,
                         child_config.maxspareservers);
            SERVER_COUNT_UNLOCK ();

            break;
        } else {
            SERVER_COUNT_UNLOCK ();
        }

        SERVER_INC ();
    }

    ptr->status = T_EMPTY;

    safefree (cliaddr);
    exit (0);
}
Example #5
0
void
hx_connect (struct htlc_conn *htlc, const char *serverstr, u_int16_t port,
	    const char *name, u_int16_t icon, const char *login, const char *pass,
	    int secure)
{
	int s;
	struct SOCKADDR_IN saddr;
	char abuf[HOSTLEN+1];

#if !defined(__WIN32__)
	if (serverstr[0] == '|' && serverstr[1]) {
		int pfds[2];
		int r;

		if (htlc->fd)
			hx_htlc_close(htlc);
		r = fd_popen(pfds, serverstr+1);
		if (r < 0) {
			hx_printf_prefix(htlc, 0, INFOPREFIX, "fd_popen(%s): %s\n",
					serverstr+1, strerror(errno));
			return;
		}
		hx_printf_prefix(htlc, 0, INFOPREFIX, "connecting through pipe %s\n", serverstr+1);
		htlc->fd = pfds[0];
		htlc->wfd = pfds[1];
		s = htlc->fd;
		fd_blocking(s, 0);
		fd_closeonexec(s, 1);
		hxd_files[s].ready_write = 0;
		hxd_files[s].ready_read = htlc_read;
		hxd_files[s].conn.htlc = htlc;
		hxd_fd_add(s);
		hxd_fd_set(s, FDR);
		if (high_fd < s)
			high_fd = s;
		s = htlc->wfd;
		fd_blocking(s, 0);
		fd_closeonexec(s, 1);
		hxd_files[s].ready_read = 0;
		hxd_files[s].ready_write = htlc_write;
		hxd_files[s].conn.htlc = htlc;
		hxd_fd_add(s);
		hxd_fd_set(s, FDW);
		if (high_fd < s)
			high_fd = s;
		goto is_pipe;
	}
#endif
#if defined(CONFIG_UNIXSOCKETS)
	else if (serverstr[0] == '!' && serverstr[1]) {
		struct sockaddr_un usaddr;

		s = socket(AF_UNIX, SOCK_STREAM, 0);
		if (s < 0) {
			hx_printf_prefix(htlc, 0, INFOPREFIX, "socket: %s\n", strerror(errno));
			return;
		}
		usaddr.sun_family = AF_UNIX;
		snprintf(usaddr.sun_path, sizeof(usaddr.sun_path), "%s", serverstr+1);

		if (htlc->fd)
			hx_htlc_close(htlc);
		if (connect(s, (struct sockaddr *)&usaddr, sizeof(usaddr))) {
			switch (errno) {
				case EINPROGRESS:
					break;
				default:
					hx_printf_prefix(htlc, 0, INFOPREFIX, "connect: %s\n", strerror(errno));
					socket_close(s);
					return;
			}
		}
		htlc->usockaddr = usaddr;
		socket_blocking(s, 0);
		fd_closeonexec(s, 1);
		goto is_unix;
	}
#endif

	s = socket(AFINET, SOCK_STREAM, IPPROTO_TCP);
	if (s < 0) {
		hx_printf_prefix(htlc, 0, INFOPREFIX, "socket: %s\n", strerror(errno));
		return;
	}
	if (s >= hxd_open_max) {
		hx_printf_prefix(htlc, 0, INFOPREFIX, "%s:%d: %d >= hxd_open_max (%d)", __FILE__, __LINE__, s, hxd_open_max);
		close(s);
		return;
	}
	socket_blocking(s, 0);
	fd_closeonexec(s, 1);

	if (hx_hostname[0]) {
#ifdef CONFIG_IPV6
		if (!inet_pton(AFINET, hx_hostname, &saddr.SIN_ADDR)) {
#else
		if (!inet_aton(hx_hostname, &saddr.SIN_ADDR)) {
#endif
			struct hostent *he;

			if ((he = gethostbyname(hx_hostname))) {
				size_t len = (unsigned int)he->h_length > sizeof(struct IN_ADDR)
					     ? sizeof(struct IN_ADDR) : (unsigned int)he->h_length;
				memcpy(&saddr.SIN_ADDR, he->h_addr, len);
			} else {
#ifndef HAVE_HSTRERROR
				hx_printf_prefix(htlc, 0, INFOPREFIX, "DNS lookup for %s failed\n", hx_hostname);
#else
				hx_printf_prefix(htlc, 0, INFOPREFIX, "DNS lookup for %s failed: %s\n", hx_hostname, hstrerror(h_errno));
#endif
				socket_close(s);
				return;
			}
		}
		saddr.SIN_PORT = 0;
		saddr.SIN_FAMILY = AFINET;
		if (bind(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
			inaddr2str(abuf, &saddr);
			hx_printf_prefix(htlc, 0, INFOPREFIX, "bind %s (%s): %s\n", hx_hostname, abuf, strerror(errno));
			socket_close(s);
			return;
		}
	}

#ifdef CONFIG_IPV6
	if (!inet_pton(AFINET, serverstr, &saddr.SIN_ADDR)) {
#else
	if (!inet_aton(serverstr, &saddr.SIN_ADDR)) {
#endif
		struct hostent *he;

		if ((he = gethostbyname(serverstr))) {
			size_t len = (unsigned int)he->h_length > sizeof(struct IN_ADDR)
				     ? sizeof(struct IN_ADDR) : (unsigned int)he->h_length;
			memcpy(&saddr.SIN_ADDR, he->h_addr, len);
		} else {
#ifndef HAVE_HSTRERROR
			hx_printf_prefix(htlc, 0, INFOPREFIX, "DNS lookup for %s failed\n", serverstr);
#else
			hx_printf_prefix(htlc, 0, INFOPREFIX, "DNS lookup for %s failed: %s\n", serverstr, hstrerror(h_errno));
#endif
			socket_close(s);
			return;
		}
	}
	saddr.SIN_PORT = htons(port);
	saddr.SIN_FAMILY = AFINET;

	if (htlc->fd)
		hx_htlc_close(htlc);
	if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr))) {
#if !defined(__WIN32__)
		switch (errno) {
			case EINPROGRESS:
				break;
			default:
				hx_printf_prefix(htlc, 0, INFOPREFIX, "connect: %s\n", strerror(errno));
				socket_close(s);
				return;
		}
#else
		int wsaerr;
		wsaerr = WSAGetLastError();
		if (wsaerr != WSAEWOULDBLOCK) {
			hx_printf_prefix(htlc, 0, INFOPREFIX, "connect: WSA error %d\n", wsaerr);
			socket_close(s);
			return;
		}
#endif
	}
	htlc->sockaddr = saddr;
	inaddr2str(abuf, &saddr);
	hx_printf_prefix(htlc, 0, INFOPREFIX, "connecting to %s:%u\n", abuf, ntohs(saddr.SIN_PORT));

is_unix:
	hxd_files[s].ready_read = htlc_read;
	hxd_files[s].ready_write = htlc_write_connect;
	hxd_files[s].conn.htlc = htlc;
	hxd_fd_add(s);
	hxd_fd_set(s, FDR|FDW);
	htlc->fd = s;

is_pipe:
	hx_output.status();

	if (name)
		strlcpy(htlc->name, name, sizeof(htlc->name));
	if (icon)
		htlc->icon = icon;
	if (login)
		strlcpy(htlc->login, login, sizeof(htlc->login));
	if (pass)
		strlcpy(htlc->password, pass, sizeof(htlc->password));
	else
		htlc->password[0] = 0;
	htlc->secure = secure;
	htlc->flags.in_login = 1;
	htlc->rcv = hx_rcv_magic;
	htlc->trans = 1;
	memset(&htlc->in, 0, sizeof(struct qbuf));
	memset(&htlc->out, 0, sizeof(struct qbuf));
	qbuf_set(&htlc->in, 0, HTLS_MAGIC_LEN);
	qbuf_add(&htlc->out, HTLC_MAGIC, HTLC_MAGIC_LEN);
}

void
hx_connect_finish (struct htlc_conn *htlc)
{
	char enclogin[64], encpass[64];
	char abuf[HOSTLEN+1];
	u_int16_t icon16;
	u_int16_t llen, plen;
	int secure;
	u_int8_t *login, *pass;

	secure = htlc->secure;
	login = htlc->login;
	pass = htlc->password;
	inaddr2str(abuf, &htlc->sockaddr);
#ifdef CONFIG_HOPE
	if (secure) {
#ifdef CONFIG_CIPHER
		u_int8_t cipheralglist[64];
		u_int16_t cipheralglistlen;
		u_int8_t cipherlen;
#endif
#ifdef CONFIG_COMPRESS
		u_int8_t compressalglist[64];
		u_int16_t compressalglistlen;
		u_int8_t compresslen;
#endif
		u_int16_t hc;
		u_int8_t macalglist[64];
		u_int16_t macalglistlen;

		abuf[0] = 0;
		task_new(htlc, rcv_task_login, htlc, 0, "login");
		strcpy(htlc->macalg, "HMAC-SHA1");
		S16HTON(2, macalglist);
		macalglistlen = 2;
		macalglist[macalglistlen] = 9;
		macalglistlen++;
		memcpy(macalglist+macalglistlen, htlc->macalg, 9);
		macalglistlen += 9;
		macalglist[macalglistlen] = 8;
		macalglistlen++;
		memcpy(macalglist+macalglistlen, "HMAC-MD5", 8);
		macalglistlen += 8;

		hc = 4;
#ifdef CONFIG_COMPRESS
		if (htlc->compressalg[0]) {
			compresslen = strlen(htlc->compressalg);
			S16HTON(1, compressalglist);
			compressalglistlen = 2;
			compressalglist[compressalglistlen] = compresslen;
			compressalglistlen++;
			memcpy(compressalglist+compressalglistlen, htlc->compressalg, compresslen);
			compressalglistlen += compresslen;
			hc++;
		} else
			compressalglistlen = 0;
#endif
#ifdef CONFIG_CIPHER
		if (htlc->cipheralg[0]) {
			cipherlen = strlen(htlc->cipheralg);
			S16HTON(1, cipheralglist);
			cipheralglistlen = 2;
			cipheralglist[cipheralglistlen] = cipherlen;
			cipheralglistlen++;
			memcpy(cipheralglist+cipheralglistlen, htlc->cipheralg, cipherlen);
			cipheralglistlen += cipherlen;
			hc++;
		} else
			cipheralglistlen = 0;
#endif
		hlwrite(htlc, HTLC_HDR_LOGIN, 0, hc,
			HTLC_DATA_LOGIN, 1, abuf,
			HTLC_DATA_PASSWORD, 1, abuf,
			HTLC_DATA_MAC_ALG, macalglistlen, macalglist,
#ifdef CONFIG_CIPHER
			HTLC_DATA_CIPHER_ALG, cipheralglistlen, cipheralglist,
#endif
#ifdef CONFIG_COMPRESS
			HTLC_DATA_COMPRESS_ALG, compressalglistlen, compressalglist,
#endif
			HTLC_DATA_SESSIONKEY, 0, 0);
		return;
	}
#endif /* HOPE */

	task_new(htlc, rcv_task_login, 0, 0, "login");

	icon16 = htons(htlc->icon);
	if (login) {
		llen = strlen(login);
		if (llen > 32)
			llen = 32;
		hl_encode(enclogin, login, llen);
	} else
		llen = 0;
	htlc->clientversion = g_clientversion;
	if (htlc->clientversion >= 150) {
		if (pass) {
			u_int16_t cv = htons(185);
			plen = strlen(pass);
			if (plen > 32)
				plen = 32;
			hl_encode(encpass, pass, plen);
			hlwrite(htlc, HTLC_HDR_LOGIN, 0, 3,
				HTLC_DATA_LOGIN, llen, enclogin,
				HTLC_DATA_PASSWORD, plen, encpass,
				HTLC_DATA_CLIENTVERSION, 2, &cv);
		} else {
			u_int16_t cv = htons(185);
			hlwrite(htlc, HTLC_HDR_LOGIN, 0, 2,
				HTLC_DATA_LOGIN, llen, enclogin,
				HTLC_DATA_CLIENTVERSION, 2, &cv);
		}
	} else { /* 123 */
		if (pass) {
			plen = strlen(pass);
			if (plen > 32)
				plen = 32;
			hl_encode(encpass, pass, plen);
			hlwrite(htlc, HTLC_HDR_LOGIN, 0, 4,
				HTLC_DATA_ICON, 2, &icon16,
				HTLC_DATA_LOGIN, llen, enclogin,
				HTLC_DATA_PASSWORD, plen, encpass,
				HTLC_DATA_NAME, strlen(htlc->name), htlc->name);
		} else {
			hlwrite(htlc, HTLC_HDR_LOGIN, 0, 3,
				HTLC_DATA_ICON, 2, &icon16,
				HTLC_DATA_LOGIN, llen, enclogin,
				HTLC_DATA_NAME, strlen(htlc->name), htlc->name);
		}
	}
	memset(htlc->password, 0, sizeof(htlc->password));
}