Ejemplo n.º 1
0
void serve_file(dict_epoll_data *ptr, char *uri) {
    struct stat sbuf;
    int conn_sock = ptr->sock_fd;
    int ffd = open(uri, O_RDONLY);
#ifdef DEBUG
    printf("sock_fd: %d, openfile: %s, fd: %d\n", ptr->sock_fd, uri, ffd);
#endif
    if(ffd <= 0) {
        perror(uri);
        char *msg = "File not found";
        client_error(conn_sock, 404, "Not found", msg);
    } else {
        fstat(ffd, &sbuf);
        if(S_ISREG(sbuf.st_mode)) {
            ptr->static_fd = ffd;
            ptr->file_offset = 0;
            ptr->file_cnt = sbuf.st_size;
            serve_static(ptr, uri, sbuf.st_size); // will close ffd
        } else if(S_ISDIR(sbuf.st_mode)) {
            char *msg = "Dir listing is not impleted";
            client_error(conn_sock, 404, "Error", msg);
            close(ffd);
        } else {
            char *msg = "Unknow Error";
            client_error(conn_sock, 400, "Error", msg);
            close(ffd);
        }
    }
}
Ejemplo n.º 2
0
/* Establishes two network connections to a Postgres server: one for SQL, and one
 * for replication. context->conninfo contains the connection string or URL to connect
 * to, and context->app_name is the client name (which appears, for example, in
 * pg_stat_activity). Returns 0 on success. */
int client_connect(client_context_t context) {
    if (!context->conninfo || context->conninfo[0] == '\0') {
        client_error(context, "conninfo must be set in client context");
        return EINVAL;
    }
    if (!context->app_name || context->app_name[0] == '\0') {
        client_error(context, "app_name must be set in client context");
        return EINVAL;
    }

    context->sql_conn = PQconnectdb(context->conninfo);
    if (PQstatus(context->sql_conn) != CONNECTION_OK) {
        client_error(context, "Connection to database failed: %s", PQerrorMessage(context->sql_conn));
        return EIO;
    }

    /* Parse the connection string into key-value pairs */
    char *error = NULL;
    PQconninfoOption *parsed_opts = PQconninfoParse(context->conninfo, &error);
    if (!parsed_opts) {
        client_error(context, "Replication connection info: %s", error);
        PQfreemem(error);
        return EIO;
    }

    /* Copy the key-value pairs into a new structure with added replication options */
    PQconninfoOption *option;
    int optcount = 2; /* replication, fallback_application_name */
    for (option = parsed_opts; option->keyword != NULL; option++) {
        if (option->val != NULL && option->val[0] != '\0') optcount++;
    }

    const char **keys = malloc((optcount + 1) * sizeof(char *));
    const char **values = malloc((optcount + 1) * sizeof(char *));
    int i = 0;

    for (option = parsed_opts; option->keyword != NULL; option++) {
        if (option->val != NULL && option->val[0] != '\0') {
            keys[i] = option->keyword;
            values[i] = option->val;
            i++;
        }
    }

    keys[i] = "replication";               values[i] = "database";        i++;
    keys[i] = "fallback_application_name"; values[i] = context->app_name; i++;
    keys[i] = NULL;                        values[i] = NULL;

    int err = 0;
    context->repl.conn = PQconnectdbParams(keys, values, true);
    if (PQstatus(context->repl.conn) != CONNECTION_OK) {
        client_error(context, "Replication connection failed: %s", PQerrorMessage(context->repl.conn));
        err = EIO;
    }

    free(keys);
    free(values);
    PQconninfoFree(parsed_opts);
    return err;
}
Ejemplo n.º 3
0
static void on_connect(void *ud, zn_Tcp *tcp, unsigned err) {
    if (err != ZN_OK)
        client_error(tcp);
    else if (zn_send(tcp, client.send, BLOCK_SIZE, on_client_send, &client) != ZN_OK)
        client_error(tcp);
    else if (zn_recv(tcp, client.recv, BLOCK_SIZE, on_client_recv, &client) != ZN_OK)
        client_error(tcp);
}
Ejemplo n.º 4
0
static void on_client_send(void *ud, zn_Tcp *tcp, unsigned err, unsigned count) {
    Userdata *data = (Userdata*)ud;
    if (err != ZN_OK) {
        ++data->send_err;
        client_error(tcp);
        return;
    }
    ++data->send_ok;
    data->send_bytes += count;
    if (zn_send(tcp, data->send, BLOCK_SIZE, on_client_send, ud) != ZN_OK)
        client_error(tcp);
}
Ejemplo n.º 5
0
// 处理HTTP事务
void doit(int fd)
{
    int is_static;
    struct stat sbuf;
    char buf[LINE_MAX], method[LINE_MAX], uri[LINE_MAX], version[LINE_MAX];
    char filename[LINE_MAX], cgiargs[LINE_MAX];

    // 读入请求行
    readline(fd, buf, sizeof(buf));
    sscanf(buf, "%s %s %s", method, uri, version);

    // 读入请求报头,简单打印到标准输出
    while (readline(fd, buf, sizeof(buf)))
    {
        printf("%s", buf);
        if (strcmp(buf, "\r\n") == 0)
            break;
    }

    if (strcmp(method, "GET"))
    {
        client_error(fd, method, "501", "Impelementd", "minihttp does not impelement this method");
        return;
    }

    is_static = parse_uri(uri, filename, cgiargs);
    if (stat(filename, &sbuf) < 0)
    {
        client_error(fd, filename, "404", "Not found", "miniftp couldn't find this file");
        return;
    }

    if (is_static) /* Serve static content */
    {
        if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode))
        {
            client_error(fd, filename, "403", "Forbidden", "minihttp couldn't read the file");
            return;
        }
        serve_static(fd, filename, sbuf.st_size);
    }
    else /* Serve dynamic content */
    {
        if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode))
        {
            client_error(fd, filename, "403", "Forbidden", "minihttp couldn't run the CGI program");
            return;
        } 
        serve_dynamic(fd, filename, cgiargs);
    }

}
Ejemplo n.º 6
0
// handle one HTTP request/response transaction
void process(int fd, struct sockaddr_in *clientaddr){
	printf("Accept Request, fd is %d, pid is %d\n", fd, getpid());

	http_request req;
	memset(&req, 0, sizeof(req));
	if (-1 == parse_request(fd, &req)) {
		//bad socket, don't record
		printf("Invalid socket!\n");
		return;
	}
	
	//update recent visited client information
	char browser[10][100];
	char ip[10][100];
	memset(browser, 0, 1000);
	memset(ip, 0, 1000);
	strcpy(browser[0], browser_name[req.browser_index]);
	strcpy(ip[0], inet_ntoa(clientaddr->sin_addr));
	update(browser, ip);
	

	struct stat sbuf;
	int status = 200; //server status init as 200
	int ffd = open(req.filename, O_RDONLY, 0);
	if(ffd <= 0){
		// detect 404 error and print error log
		status = 404;
		client_error(fd, status, "Not Found", "File Not Found");
		
	} else {
		// get descriptor status
		fstat(ffd, &sbuf);
		if(S_ISREG(sbuf.st_mode)){
			// server serves static content
			serve_static(fd, ffd, &req, status);
		} else if(S_ISDIR(sbuf.st_mode)){
			// server handle directory request
			handle_directory_request(fd, status, browser, ip);
		} else {
			// detect 400 error and print error log
			status = 400;
			client_error(fd, status, "Bad Request", "Bad Request");
		}
		close(ffd);
	}
	
	// print log/status on the terminal
	log_access(status, clientaddr, &req);
}
Ejemplo n.º 7
0
/* Reads the next result row from the snapshot query, parses and processes it.
 * Blocks until a new row is available, if necessary. */
int snapshot_poll(client_context_t context) {
    int err = 0;
    PGresult *res = PQgetResult(context->sql_conn);

    /* null result indicates that there are no more rows */
    if (!res) {
        check(err, exec_sql(context, "COMMIT"));
        PQfinish(context->sql_conn);
        context->sql_conn = NULL;

        // Invoke the commit callback with xid==0 to indicate end of snapshot
        commit_txn_cb on_commit = context->repl.frame_reader->on_commit_txn;
        void *cb_context = context->repl.frame_reader->cb_context;
        if (on_commit) {
            check(err, on_commit(cb_context, context->repl.start_lsn, 0));
        }
        return 0;
    }

    ExecStatusType status = PQresultStatus(res);
    if (status != PGRES_SINGLE_TUPLE && status != PGRES_TUPLES_OK) {
        client_error(context, "While reading snapshot: %s: %s",
                PQresStatus(PQresultStatus(res)),
                PQresultErrorMessage(res));
        PQclear(res);
        return EIO;
    }

    int tuples = PQntuples(res);
    for (int tuple = 0; tuple < tuples; tuple++) {
        check(err, snapshot_tuple(context, res, tuple));
    }
    PQclear(res);
    return err;
}
Ejemplo n.º 8
0
/**
 * Mark clients as having sent status as specified by PRSTATUS
 */
void set_proxy_status(struct finfo_t *finfo, const unsigned char *data,
                      int hostidx, int nak_count)
{
    struct prstatus_h *prstatus;
    uint32_t *addrlist;
    int clientcnt, clientidx, dupmsg, i;

    prstatus = (struct prstatus_h *)data;
    addrlist = (uint32_t *)(data + sizeof(struct prstatus_h));

    clientcnt = ntohs(prstatus->destcount);
    for (i = 0; i < clientcnt; i++) {
        clientidx = find_client(addrlist[i]);
        if (clientidx == -1) {
            log1(0, 0, "Client %s via proxy %s not found",
                       inet_ntoa(to_addr(addrlist[i])), destlist[hostidx].name);
        } else if (destlist[clientidx].proxyidx != hostidx) {
            log1(0, 0, "Client %s found via proxy %s, expected proxy %s",
                        destlist[clientidx].name,
                        destlist[destlist[clientidx].proxyidx].name,
                        destlist[hostidx].name);
        } else if (!client_error(clientidx)) {
            dupmsg = (destlist[clientidx].status == DEST_ACTIVE);
            destlist[clientidx].status = DEST_ACTIVE;
            log(0, 0, "  For client%s %s", dupmsg ? "+" : "",
                       destlist[clientidx].name);
            if (!dupmsg) {
                finfo->deststate[clientidx].naks += nak_count;
            }
        }
    }
}
Ejemplo n.º 9
0
static void on_connect(void *ud, zn_Tcp *tcp, unsigned err) {
    zn_BufferPoolNode *data = (zn_BufferPoolNode*)ud;

    if (err != ZN_OK) {
        client_error(tcp, ud);
        return;
    }

    if (zn_recv(tcp, zn_recvbuff(&data->recv), zn_recvsize(&data->recv),
                on_client_recv, ud) != ZN_OK)
        client_error(tcp, ud);
    else if (zn_sendprepare(&data->send, send_data, BLOCK_SIZE)
            && zn_send(tcp, zn_sendbuff(&data->send), zn_sendsize(&data->send),
                on_client_send, ud) != ZN_OK)
        client_error(tcp, ud);
}
Ejemplo n.º 10
0
static void on_client_packet(void *ud, const char *buff, size_t len) {
    zn_BufferPoolNode *data = (zn_BufferPoolNode*)ud;
    if (zn_sendprepare(&data->send, buff, len)
            && zn_send(data->tcp, zn_sendbuff(&data->send), zn_sendsize(&data->send),
                on_client_send, ud) != ZN_OK)
        client_error(data->tcp, ud);
}
Ejemplo n.º 11
0
int			put_client(int sock, char *cmd)
{
	char	**tab;
	int		fd;

	tab = ft_strsplit(cmd, ' ');
	if (!tab[1])
		return (client_error(-2));
	fd = open(tab[1], O_RDONLY);
	if (fd == -1)
		return (client_error(-3));
	send(sock, cmd, ft_strlen(cmd), 0);
	file_to_sock(sock, fd);
	printf("SUCCESS: file %s has been sent to server\n", tab[1]);
	ft_tabfree(&tab);
	return (0);
}
Ejemplo n.º 12
0
void		*xmalloc(size_t size)
{
  void		*ptr;

  if ((ptr = malloc(size)) == NULL)
    client_error("malloc failed");
  return (ptr);
}
Ejemplo n.º 13
0
void client_send(Client *client, char *m) {
    int n;
    char buff[BUFFER_SIZE];

    Message msg;
    msg.type = MSG_TEXT;

    TextMessage payload;
    strncpy(payload.content, m, strlen(m));
    msg.text = payload;
    n = write(client->socket, &msg, sizeof(msg));
    if (n < 0) client_error("writing to socket");

    bzero(buff, BUFFER_SIZE);
    n = read(client->socket, buff, BUFFER_SIZE);
    if (n < 0) client_error("reading to socket");

    client->handler(buff);
}
Ejemplo n.º 14
0
/* Executes a SQL command that returns no results. */
int exec_sql(client_context_t context, char *query) {
    PGresult *res = PQexec(context->sql_conn, query);
    if (PQresultStatus(res) == PGRES_COMMAND_OK) {
        PQclear(res);
        return 0;
    } else {
        client_error(context, "Query failed: %s: %s", query, PQerrorMessage(context->sql_conn));
        PQclear(res);
        return EIO;
    }
}
Ejemplo n.º 15
0
/* Blocks until more data is received from the server. You don't have to use
 * this if you have your own select loop. */
int db_client_wait(client_context_t context) {
    fd_set input_mask;
    FD_ZERO(&input_mask);

    int rep_fd = PQsocket(context->repl.conn);
    int max_fd = rep_fd;
    FD_SET(rep_fd, &input_mask);

    if (context->sql_conn) {
        int sql_fd = PQsocket(context->sql_conn);
        if (sql_fd > max_fd) max_fd = sql_fd;
        FD_SET(sql_fd, &input_mask);
    }

    struct timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    int ret = select(max_fd + 1, &input_mask, NULL, NULL, &timeout);

    if (ret == 0 || (ret < 0 && errno == EINTR)) {
        return 0; /* timeout or signal */
    }
    if (ret < 0) {
        client_error(context, "select() failed: %s", strerror(errno));
        return errno;
    }

    /* Data has arrived on the socket */
    if (!PQconsumeInput(context->repl.conn)) {
        client_error(context, "Could not receive replication data: %s",
                PQerrorMessage(context->repl.conn));
        return EIO;
    }
    if (context->sql_conn && !PQconsumeInput(context->sql_conn)) {
        client_error(context, "Could not receive snapshot data: %s",
                PQerrorMessage(context->sql_conn));
        return EIO;
    }
    return 0;
}
Ejemplo n.º 16
0
/* Initiates the non-blocking capture of a consistent snapshot of the database,
 * using the exported snapshot context->repl.snapshot_name. */
int snapshot_start(client_context_t context) {
    if (!context->repl.snapshot_name || context->repl.snapshot_name[0] == '\0') {
        client_error(context, "snapshot_name must be set in client context");
        return EINVAL;
    }

    int err = 0;
    check(err, exec_sql(context, "BEGIN"));
    check(err, exec_sql(context, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"));

    PQExpBuffer query = createPQExpBuffer();
    appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT '%s'", context->repl.snapshot_name);
    check(err, exec_sql(context, query->data));
    destroyPQExpBuffer(query);

    Oid argtypes[] = { 25, 16 }; // 25 == TEXTOID, 16 == BOOLOID
    const char *args[] = { "%", context->allow_unkeyed ? "t" : "f" };

    if (!PQsendQueryParams(context->sql_conn,
                "SELECT bottledwater_export(table_pattern := $1, allow_unkeyed := $2)",
                2, argtypes, args, NULL, NULL, 1)) { // The final 1 requests results in binary format
        client_error(context, "Could not dispatch snapshot fetch: %s",
                PQerrorMessage(context->sql_conn));
        return EIO;
    }

    if (!PQsetSingleRowMode(context->sql_conn)) {
        client_error(context, "Could not activate single-row mode");
        return EIO;
    }

    // Invoke the begin-transaction callback with xid==0 to indicate start of snapshot
    begin_txn_cb begin_txn = context->repl.frame_reader->on_begin_txn;
    void *cb_context = context->repl.frame_reader->cb_context;
    if (begin_txn) {
        check(err, begin_txn(cb_context, context->repl.start_lsn, 0));
    }
    return 0;
}
Ejemplo n.º 17
0
/* Processes one tuple of the snapshot query result set. */
int snapshot_tuple(client_context_t context, PGresult *res, int row_number) {
    if (PQnfields(res) != 1) {
        client_error(context, "Unexpected response with %d fields", PQnfields(res));
        return EIO;
    }
    if (PQgetisnull(res, row_number, 0)) {
        client_error(context, "Unexpected null response value");
        return EIO;
    }
    if (PQfformat(res, 0) != 1) { /* format 1 == binary */
        client_error(context, "Unexpected response format: %d", PQfformat(res, 0));
        return EIO;
    }

    /* wal_pos == 0 == InvalidXLogRecPtr */
    int err = parse_frame(context->repl.frame_reader, 0, PQgetvalue(res, row_number, 0),
            PQgetlength(res, row_number, 0));
    if (err) {
        client_error(context, "Error parsing frame data: %s", avro_strerror());
    }
    return err;
}
Ejemplo n.º 18
0
static void on_client_send(void *ud, zn_Tcp *tcp, unsigned err, unsigned count) {
    zn_BufferPoolNode *data = (zn_BufferPoolNode*)ud;
    if (err != ZN_OK) {
        ++send_err;
        client_error(tcp, data);
        return;
    }
    ++send_ok;
    send_bytes += count;
    if (zn_sendfinish(&data->send, count))
        zn_send(tcp, zn_sendbuff(&data->send), zn_sendsize(&data->send),
                on_client_send, ud);
}
Ejemplo n.º 19
0
    void
    do_request(http::request<Body> const& req, beast::error_code& ec)
    {
        // verb must be get
        if(req.method() != http::verb::get)
        {
            http::write(sock_, client_error(http::status::bad_request, "Unsupported method"), ec);
            return;
        }

        // Request path must be absolute and not contain "..".
        if( req.target().empty() ||
            req.target()[0] != '/' ||
            req.target().find("..") != std::string::npos)
        {
            http::write(sock_, client_error(http::status::not_found, "File not found"), ec);
            return;
        }

        auto full_path = root_.to_string();
        full_path.append(req.target().data(), req.target().size());

        beast::error_code file_ec;
        auto res = get(full_path, file_ec);

        if(file_ec == beast::errc::no_such_file_or_directory)
        {
            http::write(sock_, not_found(), ec);
        }
        else if(ec)
        {
            http::write(sock_, server_error(file_ec), ec);
        }
        else
        {
            http::serializer<false, decltype(res)::body_type> sr{res};
            http::write(sock_, sr, ec);
        }
    }
Ejemplo n.º 20
0
int			main(int ac, char **av)
{
	int		port;
	int		sock;

	if (ac != 3)
		return (client_error(-1));
	port = ft_atoi(av[2]);
	sock = create_client(av[1], port);
	if (sock == -1)
		return (-1);
	make_client(sock);
	return (0);
}
Ejemplo n.º 21
0
static void on_client_recv(void *ud, zn_Tcp *tcp, unsigned err, unsigned count) {
    zn_BufferPoolNode *data = (zn_BufferPoolNode*)ud;
    if (err != ZN_OK) {
        ++recv_err;
        client_error(tcp, data);
        return;
    }

    ++recv_ok;
    recv_bytes += count;
    zn_recvfinish(&data->recv, count);
    zn_recv(tcp, zn_recvbuff(&data->recv), zn_recvsize(&data->recv),
            on_client_recv, ud);
}
Ejemplo n.º 22
0
/* Sets *exists to true if a replication slot with the name context->repl.slot_name
 * already exists, and false if not. In addition, if the slot already exists,
 * context->repl.start_lsn is filled in with the LSN at which the client should
 * restart streaming. */
int replication_slot_exists(client_context_t context, bool *exists) {
    if (!context->repl.slot_name || context->repl.slot_name[0] == '\0') {
        client_error(context, "repl.slot_name must be set in client context");
        return EINVAL;
    }

    int err = 0;
    Oid argtypes[] = { 19 }; // 19 == NAMEOID
    const char *args[] = { context->repl.slot_name };

    PGresult *res = PQexecParams(context->sql_conn,
            "SELECT restart_lsn FROM pg_replication_slots where slot_name = $1",
            1, argtypes, args, NULL, NULL, 0);
    if (PQresultStatus(res) != PGRES_TUPLES_OK) {
        client_error(context, "Could not check for existing replication slot: %s",
                PQerrorMessage(context->sql_conn));
        err = EIO;
        goto done;
    }

    *exists = (PQntuples(res) > 0 && !PQgetisnull(res, 0, 0));

    if (*exists) {
        uint32 h32, l32;
        if (sscanf(PQgetvalue(res, 0, 0), "%X/%X", &h32, &l32) != 2) {
            client_error(context, "Could not parse restart LSN: \"%s\"", PQgetvalue(res, 0, 0));
            err = EIO;
            goto done;
        } else {
            context->repl.start_lsn = ((uint64) h32) << 32 | l32;
        }
    }

done:
    PQclear(res);
    return err;
}
Ejemplo n.º 23
0
int			get_client(int sock, char *cmd)
{
	char	**tab;
	int		ret;
	char	buf[BUFF_LEN + 1];

	tab = ft_strsplit(cmd, ' ');
	if (!tab[1])
		return (client_error(-4));
	send(sock, cmd, ft_strlen(cmd), 0);
	ret = recv(sock, buf, BUFF_LEN, 0);
	buf[ret] = '\0';
	if (!ft_strcmp(GET_FAIL, buf))
	{
		printf("ERROR: You failed to receive the file: %s\n", tab[1]);
		return (0);
	}
	else if (!ft_strcmp(GET_OK, buf))
		ft_get_file(tab[1], sock);
	ft_tabfree(&tab);
	return (0);
}
Ejemplo n.º 24
0
/**
 * Perform the Announce/Register phase for a particular group/file
 * Group & encryption: ->ANNOUNCE <-REGISTER ->KEYINFO <-INFO_ACK
 * Group & no encryption: ->ANNOUNCE <-REGISTER ->REG_CONF
 * Files within a group: ->FILEINFO <-INFO_ACK
 * If client_key == 1, REGISTER is followed by CLIENT_KEY
 * Returns 1 if at least one client responded, 0 if none responded
 */
int announce_phase(struct finfo_t *finfo)
{
    time_t endtime;
    int attempt, resend, announce, regconf, keyinfo, fileinfo, open, anyerror;
    int len, rval, rcv_status, last_pass, gotall, gotone, allreg, regdone, i;
    unsigned char *packet, *decrypted;
    struct uftp_h *header;
    struct timeval timeout;
    struct sockaddr_in receiver;

    if (finfo->file_id) {
        log1(0, 0, "File ID: %04X  Name: %s", finfo->file_id, finfo->filename);
        log1(0, 0, "  sending as: %s", finfo->destfname);
        switch (finfo->ftype) {
        case FTYPE_REG:
            log(0, 0, "Bytes: %s  Blocks: %d  Sections: %d", 
                       printll(finfo->size), finfo->blocks, finfo->sections);
            break;
        case FTYPE_DIR:
            log(0, 0, "Empty directory");
            break;
        case FTYPE_LINK:
            log(0, 0, "Symbolic link to %s", finfo->linkname);
            break;
        }
    } else {
        log(0, 0, "Initializing group");
        if (sync_mode) {
            log0(0, 0, "- Connect -");
        }
    }

    rval = 1;
    packet = calloc(mtu, 1);
    decrypted = calloc(mtu, 1);
    if ((packet == NULL) || (decrypted == NULL)) {
        syserror(0, 0, "calloc failed!");
        exit(1);
    }
    header = (struct uftp_h *)packet;
    endtime = time(NULL) + announce_time;
    announce = (finfo->file_id == 0);
    regconf = (announce && (keytype == KEY_NONE));
    keyinfo = (announce && (keytype != KEY_NONE));
    fileinfo = (finfo->file_id != 0);
    open = (destcount == 0);
    for (i = 0; i < destcount; i++) {
        // At start of group, initialize all clients/proxies to DEST_MUTE.
        // At start of file, initialize proxies to DEST_ACTIVE (since they
        // don't respond directly to a FILEINFO) and clients to DEST_REGISTERED.
        if (announce) {
            destlist[i].status = DEST_MUTE;
        } else if (!client_error(i)) {
            if (destlist[i].clientcnt != -1) {
                destlist[i].status = DEST_ACTIVE;
            } else {
                destlist[i].status = DEST_REGISTERED;
            }
        }
    }

    timeout.tv_sec = announce_int / 1000;
    timeout.tv_usec = (announce_int % 1000) * 1000;
    resend = 1;
    attempt = 1;
    last_pass = 0;
    regdone = 0;
    while (time(NULL) < endtime) {
        // On the initial pass, or when the announce timeout trips,
        // send any necessary messages.
        if (resend) {
            if (keyinfo && !send_keyinfo(finfo, attempt)) {
                continue;
            }
            if (announce && !send_regconf(finfo, attempt, regconf)) {
                continue;
            }
            if (fileinfo && !send_fileinfo(finfo, attempt)) {
                continue;
            }
            if (announce && !send_announce(finfo, attempt, open)) {
                continue;
            }
            resend = 0;
        }
        // TODO: Currently, the interval between sends is really an inactivity
        // timer, not the actual time between sends.  We might want to change
        // it to that, and perhaps add an extra "overage" timer in case we're
        // still processing responses when we're due to resend, that way we'll
        // always wait some minimum amount of time.
        if ((rcv_status = read_packet(sock, &receiver, packet, &len,
                                      mtu, &timeout)) == -1) {
            continue;
        } else if (rcv_status == 0) {
            attempt++;
            resend = 1;
            if (last_pass) break;
            continue;
        }
        if (!validate_packet(packet, len, finfo)) {
            continue;
        }

        if (!handle_announce_phase(packet, decrypted, &receiver, finfo,
                                   announce, open, regconf)) {
            continue;
        }
        if (!open) {
            for (i = 0, gotall = 1, allreg = 1;
                    (i < destcount) && (gotall || allreg); i++) {
                if (announce) {
                    gotall = gotall && ((destlist[i].status == DEST_ACTIVE) ||
                                        (destlist[i].status == DEST_ABORT));
                    allreg = allreg && ((destlist[i].status == DEST_ACTIVE) ||
                                (destlist[i].status == DEST_REGISTERED) ||
                                (destlist[i].status == DEST_ABORT));
                } else {
                    gotall = gotall && ((destlist[i].status == DEST_ACTIVE) ||
                                        (destlist[i].status == DEST_DONE) ||
                                        (client_error(i)));
                }
            }
            if (gotall) {
                // Break out right away if this is a file registration.
                // For group registration, do one last wait, even if 
                // encryption is enabled since we can still send a
                // REG_CONF for a client behind a proxy.
                // Change the wait interval to the client's register_int * 1.5
                // to allow for late registers.
                // Be careful not to overrun the phase timeout!
                if (finfo->file_id != 0) break;
                timeout.tv_sec = (int)(register_int / 1000 * 1.5);
                timeout.tv_usec = (int)((register_int % 1000) * 1000 * 1.5);
                if (timeout.tv_sec > endtime) {
#ifdef WINDOWS
                    timeout.tv_sec = (long)endtime;
#else
                    timeout.tv_sec = endtime;
#endif
                    timeout.tv_usec = 0;
                }
                if (!last_pass) {
                    log(0, 0, "Late registers:");
                }
                last_pass = 1;
                send_regconf(finfo, attempt + 1, regconf);
            } else if (announce && allreg && !regdone) {
                // All have registered, so don't wait to send the next message
                resend = 1;
                regdone = 1;
            }
        }
    }
    for (i = 0, gotone = 0, anyerror = 0; i < destcount; i++) {
        gotone = gotone || (((destlist[i].status == DEST_ACTIVE) || 
                             (destlist[i].status == DEST_DONE)) && 
                            (destlist[i].clientcnt == -1));
        if (destlist[i].status == DEST_REGISTERED) {
            log1(0, 0, "Couldn't get INFO_ACK from %s", destlist[i].name);
            destlist[i].status = DEST_LOST;
            anyerror = 1;
        }
        if ((destlist[i].status == DEST_MUTE) ||
                (destlist[i].status == DEST_ABORT)) {
            anyerror = 1;
        }
    }
    if (anyerror && quit_on_error) {
        log0(0, 0, "Aboring all clients");
        send_abort(finfo, "A client dropped out, aborting all",
                &receive_dest, NULL, (keytype != KEY_NONE), 0);
        for (i = 0; i < destcount; i++) {
            if (destlist[i].status == DEST_ACTIVE) {
                destlist[i].status = DEST_ABORT;
            }
        }
        rval = 0;
    }
    if (!gotone) {
        log0(0, 0, "Announce timed out");
        rval = 0;
    }
    if (open) {
        send_regconf(finfo, attempt, regconf);
    }
    if ((finfo->file_id == 0) && sync_mode) {
        for (i = 0; i < destcount; i++) {
            if (destlist[i].status == DEST_ACTIVE) {
                log0(0, 0, "CONNECT;success;%s", destlist[i].name);
            } else {
                log0(0, 0, "CONNECT;failed;%s", destlist[i].name);
            }
        }
        log0(0, 0, "- Transfer -");
    }
    free(packet);
    free(decrypted);
    return rval;
}
Ejemplo n.º 25
0
/**
 * Request NAKs from all clients.
 * Returns the aggregate number of NAKs for the section.
 */
int get_naks(struct finfo_t *finfo, unsigned int pass, unsigned int section,
             int *alldone)
{
    unsigned char *packet, *decrypted;
    struct uftp_h *header;
    struct timeval timeout;
    struct sockaddr_in receiver;
    int resend, attempt, last_pass, gotall, anyerror;
    int blocks_this_sec, section_offset;
    int rcv_status, len, nakidx, numnaks, i, j;
    time_t endtime;

    packet = calloc(mtu, 1);
    decrypted = calloc(mtu, 1);
    if ((packet == NULL) || (decrypted == NULL)) {
        syserror(0, 0, "calloc failed!");
        exit(1);
    }
    header = (struct uftp_h *)packet;

    section_offset = (blocksize * 8) * (section - 1);
    blocks_this_sec = ((section < finfo->sections) ? (blocksize * 8) :
                            (finfo->blocks % (blocksize * 8)));
    if (finfo->sections && !blocks_this_sec) blocks_this_sec = blocksize * 8;
    for (i = 0; i < blocks_this_sec; i++) {
        nakidx = i + section_offset;
        finfo->naklist[nakidx] = 0;
    }

    for (i = 0; i < destcount; i++) {
        if (client_error(i)) {
            continue;
        }
        if (destlist[i].clientcnt != -1) {
            destlist[i].status = DEST_ACTIVE;
        } else if (destlist[i].status == DEST_ACTIVE) {
            destlist[i].status = DEST_STATUS;
        }
        free(destlist[i].last_status);
        destlist[i].last_status = NULL;
        for (j = 0; j < destlist[i].last_prstatus_cnt; j++) {
            free(destlist[i].last_prstatus[j]);
            destlist[i].last_prstatus[j] = NULL;
        }
        destlist[i].last_prstatus_cnt = 0;
    }

    endtime = time(NULL) + status_time;
    timeout.tv_sec = status_int / 1000;
    timeout.tv_usec = (status_int % 1000) * 1000;
    resend = 1;
    attempt = 1;
    gotall = 0;
    last_pass = 0;
    while ((time(NULL) < endtime) && (!gotall)) {
        if (resend) {
            if (!send_doneconf(finfo, attempt)) {
                continue;
            }
            if (!send_done(finfo, attempt, pass, section)) {
                continue;
            }
            resend = 0;
        }
        // See comments in announce_phase regarding timing
        if ((rcv_status = read_packet(sock, &receiver, packet, &len,
                                      mtu, &timeout)) == -1) {
            continue;
        } else if (rcv_status == 0) {
            attempt++;
            resend = 1;
            if (last_pass) break;
            continue;
        }
        if (!validate_packet(packet, len, finfo)) {
            continue;
        }

        if (!handle_transfer_phase(packet, decrypted, &receiver,
                blocks_this_sec, section_offset, pass, section, finfo)) {
            continue;
        }
        for (i = 0, gotall = 1, *alldone = 1;
                (i < destcount) && (gotall || *alldone); i++) {
            gotall = gotall && (destlist[i].status != DEST_STATUS);
            *alldone = *alldone && ((destlist[i].status == DEST_DONE) ||
                            (client_error(i)) || (destlist[i].clientcnt != -1));
        }
        if (*alldone) {
            if (finfo->file_id != 0) break;
            // Change the wait interval to the client's done_int * 1.5
            // to allow for late completions
            timeout.tv_sec = (int)(done_int / 1000 * 1.5);
            timeout.tv_usec = (int)((done_int % 1000) * 1000 * 1.5);
            if (!last_pass) {
                log(0, 0, "Late completions:");
            }
            last_pass = 1;
            gotall = 0;
            send_doneconf(finfo, attempt + 1);
        } 
    }

    anyerror = 0;
    if (*alldone) {
        send_doneconf(finfo, attempt + 1);
    } else if (!gotall) {
        for (i = 0, *alldone = 1; i < destcount; i++) {
            if (destlist[i].status == DEST_STATUS) {
                log1(0, 0, "Couldn't get STATUS from %s", destlist[i].name);
                destlist[i].status = DEST_LOST;
                anyerror = 1;
            }
            *alldone = *alldone && ((destlist[i].status == DEST_DONE) ||
                            (client_error(i)) || (destlist[i].clientcnt != -1));
        }
    }
    if (anyerror && quit_on_error) {
        log0(0, 0, "Aboring all clients");
        send_abort(finfo, "A client dropped out, aborting all",
                &receive_dest, NULL, (keytype != KEY_NONE), 0);
        for (i = 0; i < destcount; i++) {
            if (destlist[i].status == DEST_ACTIVE) {
                destlist[i].status = DEST_ABORT;
            }
        }
        *alldone = 1;
    }

    for (i = 0, numnaks = 0; i < blocks_this_sec; i++) {
        nakidx = i + section_offset;
        if (finfo->naklist[nakidx]) {
            numnaks++;
        }
    }

    free(packet);
    free(decrypted);
    return numnaks;
}
Ejemplo n.º 26
0
// 处理HTTP事务
void* doit(void *arg)
{
    int fd = *((int *)arg);
    int is_static;
    struct stat sbuf;
    char buf[LINE_MAX] = {0}, method[LINE_MAX] = {0}, uri[LINE_MAX] = {0}, version[LINE_MAX] = {0};
    char filename[LINE_MAX] = {0}, cgiargs[LINE_MAX] = {0};

    do
    {
        // 读入请求行
        if (readline(fd, buf, sizeof(buf)) > 0)
        {
            if (sscanf(buf, "%s %s %s", method, uri, version) != 3)
            {
                client_error(fd, "GET", "501", "Not Impelemented", "error request line");
                break;
            }
        }

        // 读入请求报头,简单打印到标准输出
        while (readline(fd, buf, sizeof(buf)) > 0)
        {
            if (strcmp(buf, "\r\n") == 0)
                break;
        }

        /* 过滤所有非GET请求*/
        if (strcmp(method, "GET"))
        {
            client_error(fd, method, "501", "Not Impelementd", "minihttp does not impelement this method");
            break;
        }

        is_static = parse_uri(uri, filename, cgiargs);
        if (stat(filename, &sbuf) < 0)
        {
            client_error(fd, filename, "404", "Not found", "miniftp couldn't find this file");
            break;
        }

        if (is_static) /* Serve static content */
        {
            if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode))
            {
                client_error(fd, filename, "403", "Forbidden", "minihttp couldn't read the file");
                break;
            }
            serve_static(fd, filename, sbuf.st_size);
        }
        else /* Serve dynamic content */
        {
            if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode))
            {
                client_error(fd, filename, "403", "Forbidden", "minihttp couldn't run the CGI program");
                break;
            } 
            serve_dynamic(fd, filename, cgiargs);
        }
    } while (0);

    close(fd);
    free((int *)arg);
    return NULL;
}
Ejemplo n.º 27
0
/**
 * Save the state of a failed transfer so it can restarted later.
 */
void write_restart_file(uint32_t group_id)
{
    struct server_restart_t header;
    char restart_name[MAXFILENAME];
    char proxy_listed[MAXPROXYDEST];
    int fd, opened, i, j, proxycnt, found;

    memset(proxy_listed, 0, sizeof(proxy_listed));
    opened = 0;
    proxycnt = 0;
    for (i = 0; i < destcount; i++) {
        if ((destlist[i].clientcnt == -1) && client_error(i)) {
            if (!opened) {
                snprintf(restart_name, sizeof(restart_name),
                         "_group_%08X_restart", group_id);
                if ((fd = open(restart_name, OPENWRITE | O_CREAT | O_TRUNC,
                               0644)) == -1) {
                    syserror(0, 0, "Failed to create restart file");
                    return;
                }

                // Write header
                header.group_id = group_id;
                header.filecount = filecount;
                if (file_write(fd, &header, sizeof(header)) == -1) {
                    log(0, 0, "Failed to write header for restart file");
                    goto errexit;
                }

                // Write file list
                for (j = 0; j < filecount; j++) {
                    if (file_write(fd, filelist[j],sizeof(filelist[j])) == -1) {
                        log(0, 0, "Failed to write filename for restart file");
                        goto errexit;
                    }
                }
                opened = 1;
            }
            if (!write_restart_host(fd, i)) {
                goto errexit;
            }
            if (destlist[i].proxyidx != -1) {
                for (j = 0, found = 0; (j < proxycnt) && !found; j++) {
                    if (proxy_listed[j] == destlist[i].proxyidx) {
                        found = 1;
                    }
                }
                if (!found) {
                    if (!write_restart_host(fd, destlist[i].proxyidx)) {
                        goto errexit;
                    }
                    proxy_listed[proxycnt++] = destlist[i].proxyidx;
                }
            }
        }
    }

    if (opened) {
        close(fd);
    }
    return;

errexit:
    close(fd);
    unlink(restart_name);
}
Ejemplo n.º 28
0
/**
 * Performs the Transfer phase for a particular file
 * Returns 1 if at least one client finished, 0 if all are dropped or aborted
 */
int transfer_phase(struct finfo_t *finfo)
{
    unsigned char *packet, *encpacket, *data;
    char path[MAXPATHNAME];
    struct uftp_h *header;
    struct fileseg_h *fileseg;
    int max_time, alldone, numbytes, sent_blocks, current_naks;
    unsigned int pass, section, numnaks, block;
    struct timeval start_time, last_sent, current_sent;
    int64_t avgwait, waitcnt, overage, tdiff;
    f_offset_t offset, curr_offset;
    int file, i;

    if (finfo->file_id != 0) {
        // First check to see if all clients are already done for this file.
        // This can happen on a restart when the file finished on the
        // last attempt and responded to the FILEINFO with a COMPLETE
        for (i = 0, alldone = 1; (i < destcount) && alldone; i++) {
            alldone = alldone && ((destlist[i].status == DEST_DONE) ||
                        (client_error(i)) || (destlist[i].clientcnt != -1));
        }
        if (alldone) {
            gettimeofday(&start_time, NULL);
            print_status(finfo, start_time);
            return 1;
        }
    }

    // If rate is -1, use 100Mbps for purpose of calculating max time
    max_time = (int)floor(((double)weight / 100) *
           ((double)finfo->size / (((rate == -1) ? 100000 : rate) / 8) / 1024));
    if (max_time < min_time) {
        max_time = min_time;
    }

    if ((finfo->file_id != 0) && (finfo->ftype == FTYPE_REG)) {
        log(0, 0, "Maximum file transfer time: %d seconds", max_time);
        snprintf(path, sizeof(path), "%s%c%s", finfo->basedir, PATH_SEP,
                                               finfo->filename);
        if ((file = open(path, OPENREAD, 0)) == -1) {
            syserror(0, 0, "Error opening file");
            return 1;
        }
    } else {
        // At end of group, all non-errored client are DEST_DONE from the
        // last file, so reset them to DEST_ACTIVE to get the final COMPLETE.
        for (i = 0; i < destcount; i++) {
            if (!client_error(i)) {
                destlist[i].status = DEST_ACTIVE;
            }
        }
    }

    packet = calloc(mtu, 1);
    encpacket = calloc(mtu, 1);
    if ((packet == NULL) || (encpacket == NULL)) {
        syserror(0, 0, "calloc failed!");
        exit(1);
    }
    header = (struct uftp_h *)packet;
    fileseg = (struct fileseg_h *)(packet + sizeof(struct uftp_h));
    data = (unsigned char *)fileseg + sizeof(struct fileseg_h);
    set_uftp_header(header, FILESEG, finfo, &receive_dest);    

    pass = 1;
    alldone = 0;
    gettimeofday(&start_time, NULL);
    do {
        avgwait = 0;
        waitcnt = 0;
        numnaks = 0;
        overage = 0;
        section = 1;
        curr_offset = 0;
        sent_blocks = 0;

        gettimeofday(&last_sent, NULL);
        if (finfo->file_id != 0) {
            log(0, 0, "Sending file...pass %d", pass);
            lseek_func(file, 0, SEEK_SET);
        } else {
            log(0, 0, "Finishing group");
        }
        fileseg->func = FILESEG;
        fileseg->file_id = htons(finfo->file_id);
        fileseg->pass = pass;
        fileseg->section = htons(section);
        for (block = 0; block < finfo->blocks; block++) {
            // If all clients received this file partially on a prior attempt
            // and it's the first pass, request NAKs for all sections
            // right away and don't send any data packets.
            if (((pass == 1) || finfo->naklist[block]) &&
                    !((pass == 1) && finfo->partial)) {
                if (diff_sec(last_sent, start_time) > max_time) {
                    log0(0, 0, "Max file transfer time exceeded");
                    send_abort(finfo, "Max file transfer time exceeded",
                            &receive_dest, NULL, (keytype != KEY_NONE),
                            !quit_on_error);
                    alldone = 1;
                    for (i = 0; i < destcount; i++) {
                        if (quit_on_error || ((destlist[i].status == DEST_ACTIVE) &&
                                               destlist[i].clientcnt == -1 )) {
                            destlist[i].status = DEST_ABORT;
                        }
                    }
                    break;
                }
                // On the first pass, go straight through the file.
                // On later passes, seek to the next packet.
                if (pass != 1) {
                    log4(0, 0, "Resending %d", block);
                    if (!seek_block(file, block, &offset, curr_offset)) {
                        continue;
                    }
                }
                if ((numbytes = read(file, data, blocksize)) == -1) {
                    syserror(0, 0, "read failed");
                    continue;
                }
                if (pass != 1) {
                    curr_offset = offset + numbytes;
                }

                // Keep track of how long we really slept compared to how
                // long we expected to sleep.  If we went over, subtract the
                // time over from the next sleep time.  This way we maintain
                // the proper average sleep time.  This can result in multiple
                // packets going out at once, potentially losing packets.
                if (packet_wait > overage) {
                    usleep(packet_wait - (int32_t)overage);
                }
                gettimeofday(&current_sent, NULL);
                tdiff = diff_usec(current_sent, last_sent);
                avgwait += tdiff;
                waitcnt++;
                if (packet_wait) overage += tdiff - packet_wait;
                last_sent = current_sent;

                fileseg->seq_num = htonl(block);
                send_data(finfo, packet, numbytes, encpacket);
                sent_blocks++;
            }
            if ((block % (blocksize * 8) == (blocksize * 8) - 1) ||
                    (block == finfo->blocks - 1)) {
                if ((pass == 1) || sent_blocks) {
                    current_naks = get_naks(finfo, pass, section, &alldone);
                    numnaks += current_naks;
                    if ((rate != -1) && (cc_count > 0)) {
                        if (!read_cc_config(cc_config)) {
                            log1(0, 0, "Error rereading congestion control "
                                       "config, using prior values");
                        }
                        adjust_rate(current_naks, sent_blocks);
                    }
                    overage = 0;
                    if (alldone) break;
                }
                sent_blocks = 0;
                gettimeofday(&last_sent, NULL);
                fileseg->section = htons(++section);
            }
        }
        if ((finfo->size == 0) && !alldone) {
            // If it's the end of the group, or an empty file, a DONE was
            // never sent, so send it now
            numnaks += get_naks(finfo, pass, section, &alldone);
        }
        if (finfo->file_id != 0) {
            log(0, 0, "Average wait time = %.2f us",
                       (waitcnt == 0) ? 0 : (float)avgwait / waitcnt);
            log(0, 0, "Received %d distinct NAKs for pass %d", numnaks, pass);
        }
        pass++;
    } while (!alldone);

    if ((finfo->file_id != 0) && (finfo->ftype == FTYPE_REG)) {
        close(file);
    }
    print_status(finfo, start_time);

    free(packet);
    free(encpacket);

    for (i = 0; i < destcount; i++) {
        if (quit_on_error) {
            // Check to see that all finished
            if ((destlist[i].status != DEST_DONE) &&
                    (destlist[i].clientcnt == -1)) {
                return 0;
            }
        } else {
            // Check to see if at least one finished
            if (destlist[i].status == DEST_DONE) {
                return 1;
            }
        }
    }
    if (quit_on_error) {
        return 1;
    } else {
        return 0;
    }
}