示例#1
0
void
server_read(struct bufferevent *bufev, void *arg)
{
	struct session	*s = arg;
	size_t		 buf_avail, read;
	int		 n;

	bufferevent_settimeout(bufev, timeout, 0);

	do {
		buf_avail = sizeof s->sbuf - s->sbuf_valid;
		read = bufferevent_read(bufev, s->sbuf + s->sbuf_valid,
		    buf_avail);
		s->sbuf_valid += read;

		while ((n = get_line(s->sbuf, &s->sbuf_valid)) > 0) {
			logmsg(LOG_DEBUG, "#%d server: %s", s->id, linebuf);
			if (!server_parse(s)) {
				end_session(s);
				return;
			}
			bufferevent_write(s->client_bufev, linebuf, linelen);
		}

		if (n == -1) {
			logmsg(LOG_ERR, "#%d server reply too long or not"
			    " clean", s->id);
			end_session(s);
			return;
		}
	} while (read == buf_avail);
}
示例#2
0
static int buffer_event_set_timeouts(lua_State* L) {
	int timeout_read, timeout_write;
	le_bufferevent* ev = buffer_event_get(L, 1);
	if(!ev->ev) return 0;

	timeout_read = lua_tointeger(L, 2);
	timeout_write = lua_tointeger(L, 3);

	bufferevent_settimeout(ev->ev, timeout_read, timeout_write);
	return 0;
}
示例#3
0
文件: client.c 项目: iksaif/sockslink
void client_start_stream(Client *cl)
{
  struct bufferevent *bev = cl->client.bufev;

  cl->authenticated = true;

  bufferevent_disable(bev, EV_READ | EV_WRITE);
  bufferevent_settimeout(bev, SOCKS_IO_TIMEOUT, SOCKS_IO_TIMEOUT);
  bufferevent_setwatermark(bev, EV_READ, 0, SOCKS_STREAM_BUFSIZ);
  bufferevent_setcb(bev, on_client_read_stream, on_client_write, on_client_event, cl);
  bufferevent_enable(bev, EV_READ | EV_WRITE);

  /* there is still data available in the buffer, call next callback */
  if (EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)))
    on_client_read_stream(bev, cl);
}
示例#4
0
文件: ssh4.c 项目: kalloc/tester
int main(int argc, char **argv) {
    event_init();
    struct sockaddr_in sa;
    struct bufferevent *bev;
    int fd;
    unsigned ip;
    inet_aton("213.248.62.7",&ip);
    sa.sin_addr = *((struct in_addr *) &ip);
    sa.sin_family = AF_INET;
    sa.sin_port = htons(22);
    bzero(&sa.sin_zero, 8);
    fd=socket(AF_INET, SOCK_STREAM, 0);
    setnb(fd);
    connect(fd, (struct sockaddr *) & sa, sizeof (struct sockaddr));
    bev = bufferevent_new(fd, OnBufferedRead, OnBufferedWrite, OnBufferedError, NULL);
    bufferevent_enable(bev, EV_READ);
    bufferevent_settimeout(bev,10,10);
    event_dispatch();
    return 0;
}
示例#5
0
void ConnectTo(unsigned ip,unsigned port) {

    struct Poll *poll=malloc(sizeof(*poll));
    struct sockaddr_in sa;
    poll->IP=ip;
    poll->port=port;
    sa.sin_addr = *((struct in_addr *) &ip);
//    fprintf(stderr,cGREEN" CONNECT TO %s:%d\n"cEND,ipString(ip),poll->port);
    sa.sin_family = AF_INET;
    sa.sin_port = htons(port);
    bzero(&sa.sin_zero, 8);
    poll->fd=socket(AF_INET, SOCK_STREAM, 0);
    setnb(poll->fd);
    connect(poll->fd, (struct sockaddr *) & sa, sizeof (struct sockaddr));
    poll->bev = bufferevent_new(poll->fd, OnBufferedRead, OnBufferedWrite, OnBufferedError, poll);
    bufferevent_enable(poll->bev, EV_WRITE);
    bufferevent_settimeout(poll->bev,10,10);
    counter++;

}
示例#6
0
文件: client.c 项目: iksaif/sockslink
Client *client_new(SocksLink *sl, int fd, struct sockaddr_storage *addr,
		   socklen_t addrlen)
{
  Client *cl = calloc(sizeof (*cl), 1);
  struct bufferevent *bev;

  INIT_LIST_HEAD(&cl->next);
  INIT_LIST_HEAD(&cl->next_auth);

  if (!cl)
    return NULL;

  bev = bufferevent_new(fd, NULL, NULL, NULL, NULL);
  if (!bev) {
    free(cl);
    return NULL;
  }

  bufferevent_base_set(sl->base, bev);

  cl->client_method = AUTH_METHOD_INVALID;
  cl->server_method = AUTH_METHOD_INVALID;
  cl->parent = sl;
  cl->client.bufev = bev;
  cl->client.fd = fd;
  cl->client.addr = *addr;
  cl->client.addrlen = addrlen;
  cl->server.fd = -1;

  list_add(&cl->next, &sl->clients);

  if (sl->pipe) {
    client_connect_server(cl);
  } else {
    bufferevent_setcb(bev, on_client_read_init, on_client_write, on_client_event, cl);
    bufferevent_settimeout(bev, SOCKS5_AUTH_TIMEOUT, SOCKS5_AUTH_TIMEOUT);
    bufferevent_enable(bev, EV_READ|EV_WRITE);
  }

  return cl;
}
示例#7
0
int
server_fcgi(struct httpd *env, struct client *clt)
{
	struct server_fcgi_param	 param;
	struct server_config		*srv_conf = clt->clt_srv_conf;
	struct http_descriptor		*desc = clt->clt_descreq;
	struct fcgi_record_header	*h;
	struct fcgi_begin_request_body	*begin;
	char				 hbuf[HOST_NAME_MAX+1];
	size_t				 scriptlen;
	int				 pathlen;
	int				 fd = -1, ret;
	const char			*stripped, *p, *alias, *errstr = NULL;
	char				*str, *script = NULL;

	if (srv_conf->socket[0] == ':') {
		struct sockaddr_storage	 ss;
		in_port_t		 port;

		p = srv_conf->socket + 1;

		port = strtonum(p, 0, 0xffff, &errstr);
		if (errstr != NULL) {
			log_warn("%s: strtonum %s, %s", __func__, p, errstr);
			goto fail;
		}
		memset(&ss, 0, sizeof(ss));
		ss.ss_family = AF_INET;
		((struct sockaddr_in *)
		    &ss)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
		port = htons(port);

		if ((fd = server_socket_connect(&ss, port, srv_conf)) == -1)
			goto fail;
	} else {
		struct sockaddr_un	 sun;
		size_t			 len;

		if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
			goto fail;

		memset(&sun, 0, sizeof(sun));
		sun.sun_family = AF_UNIX;
		len = strlcpy(sun.sun_path,
		    srv_conf->socket, sizeof(sun.sun_path));
		if (len >= sizeof(sun.sun_path)) {
			errstr = "socket path to long";
			goto fail;
		}
		sun.sun_len = len;

		if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
			goto fail;
	}

	socket_set_blockmode(fd, BM_NONBLOCK);

	memset(hbuf, 0, sizeof(hbuf));
	clt->clt_fcgi_state = FCGI_READ_HEADER;
	clt->clt_fcgi_toread = sizeof(struct fcgi_record_header);

	if (clt->clt_srvevb != NULL)
		evbuffer_free(clt->clt_srvevb);

	clt->clt_srvevb = evbuffer_new();
	if (clt->clt_srvevb == NULL) {
		errstr = "failed to allocate evbuffer";
		goto fail;
	}

	close(clt->clt_fd);
	clt->clt_fd = fd;

	if (clt->clt_srvbev != NULL)
		bufferevent_free(clt->clt_srvbev);

	clt->clt_srvbev_throttled = 0;
	clt->clt_srvbev = bufferevent_new(fd, server_fcgi_read,
	    NULL, server_file_error, clt);
	if (clt->clt_srvbev == NULL) {
		errstr = "failed to allocate fcgi buffer event";
		goto fail;
	}

	memset(&param, 0, sizeof(param));

	h = (struct fcgi_record_header *)&param.buf;
	h->version = 1;
	h->type = FCGI_BEGIN_REQUEST;
	h->id = htons(1);
	h->content_len = htons(sizeof(struct fcgi_begin_request_body));
	h->padding_len = 0;

	begin = (struct fcgi_begin_request_body *)&param.buf[sizeof(struct
	    fcgi_record_header)];
	begin->role = htons(FCGI_RESPONDER);

	if (bufferevent_write(clt->clt_srvbev, &param.buf,
	    sizeof(struct fcgi_record_header) +
	    sizeof(struct fcgi_begin_request_body)) == -1) {
		errstr = "failed to write to evbuffer";
		goto fail;
	}

	h->type = FCGI_PARAMS;
	h->content_len = param.total_len = 0;

	alias = desc->http_path_alias != NULL
	    ? desc->http_path_alias
	    : desc->http_path;

	stripped = server_root_strip(alias, srv_conf->strip);
	if ((pathlen = asprintf(&script, "%s%s", srv_conf->root, stripped))
	    == -1) {
		errstr = "failed to get script name";
		goto fail;
	}

	scriptlen = path_info(script);
	/*
	 * no part of root should show up in PATH_INFO.
	 * therefore scriptlen should be >= strlen(root)
	 */
	if (scriptlen < strlen(srv_conf->root))
		scriptlen = strlen(srv_conf->root);
	if ((int)scriptlen < pathlen) {
		if (fcgi_add_param(&param, "PATH_INFO",
		    script + scriptlen, clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
		script[scriptlen] = '\0';
	} else {
		/* RFC 3875 mandates that PATH_INFO is empty if not set */
		if (fcgi_add_param(&param, "PATH_INFO", "", clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
	}

	/*
	 * calculate length of http SCRIPT_NAME:
	 * add length of stripped prefix,
	 * subtract length of prepended local root
	 */
	scriptlen += (stripped - alias) - strlen(srv_conf->root);
	if ((str = strndup(alias, scriptlen)) == NULL)
		goto fail;
	ret = fcgi_add_param(&param, "SCRIPT_NAME", str, clt);
	free(str);
	if (ret == -1) {
		errstr = "failed to encode param";
		goto fail;
	}
	if (fcgi_add_param(&param, "SCRIPT_FILENAME", script, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (desc->http_query)
		if (fcgi_add_param(&param, "QUERY_STRING", desc->http_query,
		    clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}

	if (fcgi_add_param(&param, "DOCUMENT_ROOT", srv_conf->root,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}
	if (fcgi_add_param(&param, "DOCUMENT_URI", alias,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}
	if (fcgi_add_param(&param, "GATEWAY_INTERFACE", "CGI/1.1",
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (srv_conf->flags & SRVFLAG_AUTH) {
		if (fcgi_add_param(&param, "REMOTE_USER",
		    clt->clt_remote_user, clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
	}

	/* Add HTTP_* headers */
	if (server_headers(clt, desc, server_fcgi_writeheader, &param) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (srv_conf->flags & SRVFLAG_TLS)
		if (fcgi_add_param(&param, "HTTPS", "on", clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}

	(void)print_host(&clt->clt_ss, hbuf, sizeof(hbuf));
	if (fcgi_add_param(&param, "REMOTE_ADDR", hbuf, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	(void)snprintf(hbuf, sizeof(hbuf), "%d", ntohs(clt->clt_port));
	if (fcgi_add_param(&param, "REMOTE_PORT", hbuf, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (fcgi_add_param(&param, "REQUEST_METHOD",
	    server_httpmethod_byid(desc->http_method), clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (!desc->http_query) {
		if (fcgi_add_param(&param, "REQUEST_URI", desc->http_path,
		    clt) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
	} else {
		if (asprintf(&str, "%s?%s", desc->http_path,
		    desc->http_query) == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
		ret = fcgi_add_param(&param, "REQUEST_URI", str, clt);
		free(str);
		if (ret == -1) {
			errstr = "failed to encode param";
			goto fail;
		}
	}

	(void)print_host(&clt->clt_srv_ss, hbuf, sizeof(hbuf));
	if (fcgi_add_param(&param, "SERVER_ADDR", hbuf, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	(void)snprintf(hbuf, sizeof(hbuf), "%d",
	    ntohs(server_socket_getport(&clt->clt_srv_ss)));
	if (fcgi_add_param(&param, "SERVER_PORT", hbuf, clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (fcgi_add_param(&param, "SERVER_NAME", srv_conf->name,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (fcgi_add_param(&param, "SERVER_PROTOCOL", desc->http_version,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (fcgi_add_param(&param, "SERVER_SOFTWARE", HTTPD_SERVERNAME,
	    clt) == -1) {
		errstr = "failed to encode param";
		goto fail;
	}

	if (param.total_len != 0) {	/* send last params record */
		if (bufferevent_write(clt->clt_srvbev, &param.buf,
		    sizeof(struct fcgi_record_header) +
		    ntohs(h->content_len)) == -1) {
			errstr = "failed to write to client evbuffer";
			goto fail;
		}
	}

	/* send "no more params" message */
	h->content_len = 0;
	if (bufferevent_write(clt->clt_srvbev, &param.buf,
	    sizeof(struct fcgi_record_header)) == -1) {
		errstr = "failed to write to client evbuffer";
		goto fail;
	}

	bufferevent_settimeout(clt->clt_srvbev,
	    srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
	bufferevent_enable(clt->clt_srvbev, EV_READ|EV_WRITE);
	if (clt->clt_toread != 0) {
		server_read_httpcontent(clt->clt_bev, clt);
		bufferevent_enable(clt->clt_bev, EV_READ);
	} else {
		bufferevent_disable(clt->clt_bev, EV_READ);
		fcgi_add_stdin(clt, NULL);
	}

	if (strcmp(desc->http_version, "HTTP/1.1") == 0) {
		clt->clt_fcgi_chunked = 1;
	} else {
		/* HTTP/1.0 does not support chunked encoding */
		clt->clt_fcgi_chunked = 0;
		clt->clt_persist = 0;
	}
	clt->clt_fcgi_end = 0;
	clt->clt_done = 0;

	free(script);
	return (0);
 fail:
	free(script);
	if (errstr == NULL)
		errstr = strerror(errno);
	server_abort_http(clt, 500, errstr);
	return (-1);
}
示例#8
0
文件: server_file.c 项目: Nshk/httpd
int
server_file_request(struct httpd *env, struct client *clt, char *path,
                    struct stat *st)
{
    struct server_config	*srv_conf = clt->clt_srv_conf;
    struct media_type	*media;
    const char		*errstr = NULL;
    int			 fd = -1, ret, code = 500;

    if ((ret = server_file_method(clt)) != 0) {
        code = ret;
        goto abort;
    }

    if ((ret = server_file_modified_since(clt->clt_descreq, st)) != -1)
        return ret;

    /* Now open the file, should be readable or we have another problem */
    if ((fd = open(path, O_RDONLY)) == -1)
        goto abort;

    media = media_find(env->sc_mediatypes, path);
    ret = server_response_http(clt, 200, media, st->st_size,
                               MINIMUM(time(NULL), st->st_mtim.tv_sec));
    switch (ret) {
    case -1:
        goto fail;
    case 0:
        /* Connection is already finished */
        close(fd);
        goto done;
    default:
        break;
    }

    clt->clt_fd = fd;
    if (clt->clt_srvbev != NULL)
        bufferevent_free(clt->clt_srvbev);

    clt->clt_srvbev = bufferevent_new(clt->clt_fd, server_read,
                                      server_write, server_file_error, clt);
    if (clt->clt_srvbev == NULL) {
        errstr = "failed to allocate file buffer event";
        goto fail;
    }

    /* Adjust read watermark to the socket output buffer size */
    bufferevent_setwatermark(clt->clt_srvbev, EV_READ, 0,
                             clt->clt_sndbufsiz);

    bufferevent_settimeout(clt->clt_srvbev,
                           srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
    bufferevent_enable(clt->clt_srvbev, EV_READ);
    bufferevent_disable(clt->clt_bev, EV_READ);

done:
    server_reset_http(clt);
    return (0);
fail:
    bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE);
    bufferevent_free(clt->clt_bev);
    clt->clt_bev = NULL;
abort:
    if (errstr == NULL)
        errstr = strerror(errno);
    server_abort_http(clt, code, errstr);
    return (-1);
}
示例#9
0
/**
* This function will be called by libevent when there is a connection
* ready to be accepted.
*/
void on_accept(int fd, short ev, void *arg) {
	int client_fd;
	struct sockaddr_in client_addr;
	socklen_t client_len = sizeof(client_addr);
	workqueue_t *workqueue = (workqueue_t *)arg;
	client_t *client;
	job_t *job;

	client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
	if (client_fd < 0) {
		warn("accept failed");
		return;
	}
	printf("Run accept fd:%d\n", fd);
	/* Set the client socket to non-blocking mode. */
	if (setnonblock(client_fd) < 0) {
		;
		warn("failed to set client socket to non-blocking");
		close(client_fd);
		return;
	}

	/* Create a client object. */
	if ((client = (client_t *)malloc(sizeof(*client))) == NULL) {
		warn("failed to allocate memory for client state");
		close(client_fd);
		return;
	}
	memset(client, 0, sizeof(*client));
	client->fd = client_fd;

	/* Add any custom code anywhere from here to the end of this function
	* to initialize your application-specific attributes in the client struct. */

	if ((client->output_buffer = evbuffer_new()) == NULL) {
		warn("client output buffer allocation failed");
		closeAndFreeClient(client);
		return;
	}

	if ((client->evbase = event_base_new()) == NULL) {
		warn("client event_base creation failed");
		closeAndFreeClient(client);
		return;
	}

	/* Create the buffered event.
	*
	* The first argument is the file descriptor that will trigger
	* the events, in this case the clients socket.
	*
	* The second argument is the callback that will be called
	* when data has been read from the socket and is available to
	* the application.
	*
	* The third argument is a callback to a function that will be
	* called when the write buffer has reached a low watermark.
	* That usually means that when the write buffer is 0 length,
	* this callback will be called.  It must be defined, but you
	* don't actually have to do anything in this callback.
	*
	* The fourth argument is a callback that will be called when
	* there is a socket error.  This is where you will detect
	* that the client disconnected or other socket errors.
	*
	* The fifth and final argument is to store an argument in
	* that will be passed to the callbacks.  We store the client
	* object here.
	*/
	if ((client->buf_ev = bufferevent_new(client_fd, buffered_on_read, buffered_on_write, buffered_on_error, client)) == NULL) {
		warn("client bufferevent creation failed");
		closeAndFreeClient(client);
		return;
	}
	bufferevent_base_set(client->evbase, client->buf_ev);

	bufferevent_settimeout(client->buf_ev, SOCKET_READ_TIMEOUT_SECONDS, SOCKET_WRITE_TIMEOUT_SECONDS);

	/* We have to enable it before our callbacks will be
	* called. */
	bufferevent_enable(client->buf_ev, EV_READ);

	/* Create a job object and add it to the work queue. */
	if ((job = (job_t *)malloc(sizeof(*job))) == NULL) {
		warn("failed to allocate memory for job state");
		closeAndFreeClient(client);
		return;
	}
	job->job_function = server_job_function;
	job->user_data = client;

	workqueue_add_job(workqueue, job);
}
示例#10
0
void
handle_connection(const int listen_fd, short event, void *arg)
{
	struct sockaddr_storage tmp_ss;
	struct sockaddr *client_sa, *server_sa, *fixed_server_sa;
	struct sockaddr *proxy_to_server_sa;
	struct session *s;
	socklen_t len;
	int client_fd, fc, on;

	event_add(&listen_ev, NULL);

	if ((event & EV_TIMEOUT))
		/* accept() is no longer paused. */
		return;

	/*
	 * We _must_ accept the connection, otherwise libevent will keep
	 * coming back, and we will chew up all CPU.
	 */
	client_sa = sstosa(&tmp_ss);
	len = sizeof(struct sockaddr_storage);
	if ((client_fd = accept(listen_fd, client_sa, &len)) < 0) {
		logmsg(LOG_CRIT, "accept() failed: %s", strerror(errno));

		/*
		 * Pause accept if we are out of file descriptors, or
		 * libevent will haunt us here too.
		 */
		if (errno == ENFILE || errno == EMFILE) {
			struct timeval pause = { 1, 0 };

			event_del(&listen_ev);
			evtimer_add(&pause_accept_ev, &pause);
		} else if (errno != EWOULDBLOCK && errno != EINTR &&
		    errno != ECONNABORTED)
			logmsg(LOG_CRIT, "accept() failed: %s", strerror(errno));
		return;
	}

	/* Refuse connection if the maximum is reached. */
	if (session_count >= max_sessions) {
		logmsg(LOG_ERR, "client limit (%d) reached, refusing "
		    "connection from %s", max_sessions, sock_ntop(client_sa));
		close(client_fd);
		return;
	}

	/* Allocate session and copy back the info from the accept(). */
	s = init_session();
	if (s == NULL) {
		logmsg(LOG_CRIT, "init_session failed");
		close(client_fd);
		return;
	}
	s->client_fd = client_fd;
	memcpy(sstosa(&s->client_ss), client_sa, client_sa->sa_len);

	/* Cast it once, and be done with it. */
	client_sa = sstosa(&s->client_ss);
	server_sa = sstosa(&s->server_ss);
	proxy_to_server_sa = sstosa(&s->proxy_ss);
	fixed_server_sa = sstosa(&fixed_server_ss);

	/* Log id/client early to ease debugging. */
	logmsg(LOG_DEBUG, "#%d accepted connection from %s", s->id,
	    sock_ntop(client_sa));

	/*
	 * Find out the real server and port that the client wanted.
	 */
	len = sizeof(struct sockaddr_storage);
	if (getsockname(s->client_fd, server_sa, &len) < 0) {
		logmsg(LOG_CRIT, "#%d getsockname failed: %s", s->id,
		    strerror(errno));
		goto fail;
	}
	len = sizeof(s->client_rd);
	if (getsockopt(s->client_fd, SOL_SOCKET, SO_RTABLE, &s->client_rd,
	    &len) && errno != ENOPROTOOPT) {
		logmsg(LOG_CRIT, "#%d getsockopt failed: %s", s->id,
		    strerror(errno));
		goto fail;
	}
	if (fixed_server) {
		memcpy(sstosa(&s->orig_server_ss), server_sa,
		    server_sa->sa_len);
		memcpy(server_sa, fixed_server_sa, fixed_server_sa->sa_len);
	}

	/* XXX: check we are not connecting to ourself. */

	/*
	 * Setup socket and connect to server.
	 */
	if ((s->server_fd = socket(server_sa->sa_family, SOCK_STREAM,
	    IPPROTO_TCP)) < 0) {
		logmsg(LOG_CRIT, "#%d server socket failed: %s", s->id,
		    strerror(errno));
		goto fail;
	}
	if (fixed_proxy && bind(s->server_fd, sstosa(&fixed_proxy_ss),
	    fixed_proxy_ss.ss_len) != 0) {
		logmsg(LOG_CRIT, "#%d cannot bind fixed proxy address: %s",
		    s->id, strerror(errno));
		goto fail;
	}

	/* Use non-blocking connect(), see CONNECT_TIMEOUT below. */
	if ((fc = fcntl(s->server_fd, F_GETFL)) == -1 ||
	    fcntl(s->server_fd, F_SETFL, fc | O_NONBLOCK) == -1) {
		logmsg(LOG_CRIT, "#%d cannot mark socket non-blocking: %s",
		    s->id, strerror(errno));
		goto fail;
	}
	if (connect(s->server_fd, server_sa, server_sa->sa_len) < 0 &&
	    errno != EINPROGRESS) {
		logmsg(LOG_CRIT, "#%d proxy cannot connect to server %s: %s",
		    s->id, sock_ntop(server_sa), strerror(errno));
		goto fail;
	}

	len = sizeof(struct sockaddr_storage);
	if ((getsockname(s->server_fd, proxy_to_server_sa, &len)) < 0) {
		logmsg(LOG_CRIT, "#%d getsockname failed: %s", s->id,
		    strerror(errno));
		goto fail;
	}

	logmsg(LOG_INFO, "#%d FTP session %d/%d started: client %s to server "
	    "%s via proxy %s", s->id, session_count, max_sessions,
	    sock_ntop(client_sa), sock_ntop(server_sa),
	    sock_ntop(proxy_to_server_sa));

	/* Keepalive is nice, but don't care if it fails. */
	on = 1;
	setsockopt(s->client_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
	    sizeof on);
	setsockopt(s->server_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
	    sizeof on);

	/*
	 * Setup buffered events.
	 */
	s->client_bufev = bufferevent_new(s->client_fd, &client_read, NULL,
	    &client_error, s);
	if (s->client_bufev == NULL) {
		logmsg(LOG_CRIT, "#%d bufferevent_new client failed", s->id);
		goto fail;
	}
	bufferevent_settimeout(s->client_bufev, timeout, 0);
	bufferevent_enable(s->client_bufev, EV_READ | EV_TIMEOUT);

	s->server_bufev = bufferevent_new(s->server_fd, &server_read, NULL,
	    &server_error, s);
	if (s->server_bufev == NULL) {
		logmsg(LOG_CRIT, "#%d bufferevent_new server failed", s->id);
		goto fail;
	}
	bufferevent_settimeout(s->server_bufev, CONNECT_TIMEOUT, 0);
	bufferevent_enable(s->server_bufev, EV_READ | EV_TIMEOUT);

	return;

 fail:
	end_session(s);
}
示例#11
0
文件: server_file.c 项目: reyk/httpd
int
server_partial_file_request(struct httpd *env, struct client *clt, char *path,
    struct stat *st, char *range_str)
{
	struct server_config	*srv_conf = clt->clt_srv_conf;
	struct http_descriptor	*resp = clt->clt_descresp;
	struct http_descriptor	*desc = clt->clt_descreq;
	struct media_type	*media, multipart_media;
	struct range_data	*r = &clt->clt_ranges;
	struct range		*range;
	size_t			 content_length = 0;
	int			 code = 500, fd = -1, i, nranges, ret;
	char			 content_range[64];
	const char		*errstr = NULL;

	/* Ignore range request for methods other than GET */
	if (desc->http_method != HTTP_METHOD_GET)
		return server_file_request(env, clt, path, st);

	if ((nranges = parse_ranges(clt, range_str, st->st_size)) < 1) {
		code = 416;
		(void)snprintf(content_range, sizeof(content_range),
		    "bytes */%lld", st->st_size);
		errstr = content_range;
		goto abort;
	}

	/* Now open the file, should be readable or we have another problem */
	if ((fd = open(path, O_RDONLY)) == -1)
		goto abort;

	media = media_find_config(env, srv_conf, path);
	r->range_media = media;

	if (nranges == 1) {
		range = &r->range[0];
		(void)snprintf(content_range, sizeof(content_range),
		    "bytes %lld-%lld/%lld", range->start, range->end,
		    st->st_size);
		if (kv_add(&resp->http_headers, "Content-Range",
		    content_range) == NULL)
			goto abort;

		range = &r->range[0];
		content_length += range->end - range->start + 1;
	} else {
		/* Add boundary, all parts will be handled by the callback */
		arc4random_buf(&clt->clt_boundary, sizeof(clt->clt_boundary));

		/* Calculate Content-Length of the complete multipart body */
		for (i = 0; i < nranges; i++) {
			range = &r->range[i];

			/* calculate Content-Length of the complete body */
			if ((ret = snprintf(NULL, 0,
			    "\r\n--%llu\r\n"
			    "Content-Type: %s/%s\r\n"
			    "Content-Range: bytes %lld-%lld/%lld\r\n\r\n",
			    clt->clt_boundary,
			    media->media_type, media->media_subtype,
			    range->start, range->end, st->st_size)) < 0)
				goto abort;

			/* Add data length */
			content_length += ret + range->end - range->start + 1;

		}
		if ((ret = snprintf(NULL, 0, "\r\n--%llu--\r\n",
		    clt->clt_boundary)) < 0)
			goto abort;
		content_length += ret;

		/* prepare multipart/byteranges media type */
		(void)strlcpy(multipart_media.media_type, "multipart",
		    sizeof(multipart_media.media_type));
		(void)snprintf(multipart_media.media_subtype,
		    sizeof(multipart_media.media_subtype),
		    "byteranges; boundary=%llu", clt->clt_boundary);
		media = &multipart_media;
	}

	/* Start with first range */
	r->range_toread = TOREAD_HTTP_RANGE;

	ret = server_response_http(clt, 206, media, content_length,
	    MINIMUM(time(NULL), st->st_mtim.tv_sec));
	switch (ret) {
	case -1:
		goto fail;
	case 0:
		/* Connection is already finished */
		close(fd);
		goto done;
	default:
		break;
	}

	clt->clt_fd = fd;
	if (clt->clt_srvbev != NULL)
		bufferevent_free(clt->clt_srvbev);

	clt->clt_srvbev_throttled = 0;
	clt->clt_srvbev = bufferevent_new(clt->clt_fd, server_read_httprange,
	    server_write, server_file_error, clt);
	if (clt->clt_srvbev == NULL) {
		errstr = "failed to allocate file buffer event";
		goto fail;
	}

	/* Adjust read watermark to the socket output buffer size */
	bufferevent_setwatermark(clt->clt_srvbev, EV_READ, 0,
	    clt->clt_sndbufsiz);

	bufferevent_settimeout(clt->clt_srvbev,
	    srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
	bufferevent_enable(clt->clt_srvbev, EV_READ);
	bufferevent_disable(clt->clt_bev, EV_READ);

 done:
	server_reset_http(clt);
	return (0);
 fail:
	bufferevent_disable(clt->clt_bev, EV_READ|EV_WRITE);
	bufferevent_free(clt->clt_bev);
	clt->clt_bev = NULL;
 abort:
	if (fd != -1)
		close(fd);
	if (errstr == NULL)
		errstr = strerror(errno);
	server_abort_http(clt, code, errstr);
	return (-1);
}