Ejemplo n.º 1
0
void send_file_by_fd(int sfd, int fd){
    data_t buf;
    //发送文件给客户端
    while(bzero(&buf, sizeof(buf)), (buf.len = read(fd, buf.data, sizeof(buf.data) - 1)) > 0){
        send_complete(sfd, &buf);
    }
}
Ejemplo n.º 2
0
/**
 * Sends a pending aggregate message for a given group and message
 */
void send_pending(int listidx, int pendidx)
{
    switch (group_list[listidx].pending[pendidx].msg) {
    case REGISTER:
        send_register(listidx, pendidx);
        break;
    case INFO_ACK:
        send_info_ack(listidx, pendidx, FILEINFO);
        break;
    case STATUS:
        send_status(listidx, pendidx);
        break;
    case COMPLETE:
        send_complete(listidx, pendidx);
        break;
    default:
        log(group_list[listidx].group_id, 0, "Tried to send pending on "
                "invalid type %s",
                func_name(group_list[listidx].pending[pendidx].msg));
        return;
    }
    if (group_list[listidx].pending[pendidx].count <= 0) {
        // Finish the cleanup we started in load_pending
        free(group_list[listidx].pending[pendidx].naklist);
        memset(&group_list[listidx].pending[pendidx], 0,
                sizeof(struct pr_pending_info_t));
    }
}
Ejemplo n.º 3
0
/**
 * Sends a pending aggregate message for a given group and message
 */
void send_pending(struct pr_group_list_t *group, int pendidx)
{
    switch (group->pending[pendidx].msg) {
    case REGISTER:
        send_register(group, pendidx);
        break;
    case FILEINFO_ACK:
        send_fileinfo_ack(group, pendidx);
        break;
    case STATUS:
        send_status(group, pendidx);
        break;
    case COMPLETE:
        send_complete(group, pendidx);
        break;
    default:
        glog1(group, "Tried to send pending on invalid type %s",
                     func_name(group->pending[pendidx].msg));
        return;
    }
    if ((group->pending[pendidx].count <= 0) ||
            (group->pending[pendidx].msg == STATUS)) {
        // Finish the cleanup we started in load_pending
        // Always do this for a STATUS, since we don't have a pending list
        free(group->pending[pendidx].naklist);
        memset(&group->pending[pendidx], 0, sizeof(struct pr_pending_info_t));
    }
}
Ejemplo n.º 4
0
/**
 * Send a COMPLETE with the given status in response to a FILEINFO,
 * set the phase to MIDGROUP, and reset the timeout
 */
void early_complete(struct group_list_t *group, int status, int freespace)
{
    group->phase = PHASE_MIDGROUP;
    group->fileinfo.comp_status = status;
    send_complete(group, freespace);
    print_result_status(group);
    set_timeout(group, 0);
}
static void force_completion(guint key_id)
{
	if (completion_framework) {
		GeanyDocument* doc = document_get_current();
		if (doc != NULL) {
			send_complete(doc->editor, 0);
		}
	}
}
Ejemplo n.º 6
0
void send_file_by_name(int sfd, char * file_name){
    struct stat file_stat;
    int status = stat(file_name, &file_stat);
    int fd = open(file_name, O_RDONLY);
    long file_len, offset;
    data_t buf;
    if(-1 == status || -1 == fd){
        send_status(sfd, -1);
        return;
    }
    send_status(sfd, 0);
    //接收文件续传位置
    recv(sfd, &offset, sizeof(long), 0);
    //重定位到续传位置
    lseek(fd, offset, SEEK_SET);
    //发送文件大小
    file_len = file_stat.st_size;
    send(sfd, &file_len, sizeof(long), 0);
    //发送文件内容
    if(file_len > FILE_MMAP_SIZE){//大文件采用内存映射
        int i;
        long j = 0;
        long send_len = file_len - offset;
        //char * mpt = (char *)mmap(0, send_len, PROT_READ, MAP_SHARED, fd, offset);
        char * mpt = (char *)mmap(0, send_len, PROT_READ, MAP_SHARED, fd, 0);
        while(j < send_len){
            bzero(&buf, sizeof(buf));
            for(i = 0; i < sizeof(buf.data) && j < send_len; i++, j++){
                buf.data[i] = mpt[j];
            }
            buf.len = i;
            send_complete(sfd, &buf);
        }
        munmap(mpt, send_len);
    }else{//小文件直接发送
        while(bzero(&buf, sizeof(buf)), (buf.len = read(fd, buf.data, sizeof(buf.data) - 1)) > 0){
            send_complete(sfd, &buf);
        }
    }
    close(fd);
    printf("send flie %s, %ld Bytes\n", file_name, file_len);
    fflush(stdout);
}
static gboolean on_editor_notify(GObject* obj, GeanyEditor* editor, SCNotification* nt,
                                 gpointer* user_data)
{
	if (!is_completion_file_now()) {
		return FALSE;
	}
	switch (nt->nmhdr.code) {
		case SCN_UPDATEUI:
			// TODO relocation suggestion window when typings occur scroll (e.g. editting long line)
			if (nt->updated & SC_UPDATE_SELECTION) {
				suggestWindow->close();
			}
			break;
		case SCN_MODIFIED:
			// report before insert position, after delete position
			if (edit_tracker.valid) {
				if (nt->modificationType & SC_MOD_INSERTTEXT) {
					if (nt->position == edit_tracker.start_pos + edit_tracker.text.length()) {
						std::string text(nt->text, nt->length);  // nt->text is not null term
						edit_tracker.text += text;
						suggestWindow->filter_add(text.c_str());
					} else {
						edit_tracker.valid = false;
						suggestWindow->close();
					}
				}
				if (nt->modificationType & SC_MOD_DELETETEXT) {
					// it was caused by backspace?
					if (nt->length == 1 && edit_tracker.text.length() > 0 &&
					    nt->position + 1 == edit_tracker.start_pos + edit_tracker.text.length()) {
						edit_tracker.text.erase(edit_tracker.text.size() - 1);
						suggestWindow->filter_backspace();
					} else {
						edit_tracker.valid = false;
						suggestWindow->close();
					}
				}
			}
			break;
		case SCN_CHARADDED:
			if (check_trigger_char(editor)) {
				send_complete(editor, FALSE);
			}
			break;
		default:
			break;
	}
	return FALSE;
}
Ejemplo n.º 8
0
/**
 * Read in the contents of a FILEINFO message
 * Returns 1 on success, 0 on error or ignore
 */
int read_fileinfo(struct group_list_t *group, const unsigned char *message,
                  int meslen, struct timeval rxtime)
{
    const struct fileinfo_h *fileinfo;
    const uint32_t *addrlist;
    int listlen, maxsecsize;
    const char *name, *flink, *p;

    fileinfo = (const struct fileinfo_h *)message;
    addrlist = (const uint32_t *)(message + (fileinfo->hlen * 4));
    name = (const char *)message + sizeof(struct fileinfo_h);
    flink = name + (fileinfo->namelen * 4);
    listlen = (meslen - (fileinfo->hlen * 4)) / 4;

    if ((meslen < (fileinfo->hlen * 4)) ||
            ((fileinfo->hlen * 4) < sizeof(struct fileinfo_h)) ||
            ((fileinfo->namelen * 4) > MAXPATHNAME) ||
            ((fileinfo->linklen * 4) > MAXPATHNAME) ||
            ((fileinfo->hlen * 4) != sizeof(struct fileinfo_h) +
                (fileinfo->namelen * 4) + (fileinfo->linklen * 4))) {
        glog1(group, "Rejecting FILEINFO from server: invalid message size");
        send_abort(group, "Rejecting FILEINFO: invalid message size");
        return 0;
    }
    if (!uid_in_list(addrlist, listlen)) {
        set_timeout(group, 0);
        return 0;
    }

    if (group->phase == PHASE_RECEIVING) {
        // We already got the FILEINFO, so no need to reprocess.
        // Just resend the INFO_ACK and reset the timeout
        send_fileinfo_ack(group, group->fileinfo.restart);
        set_timeout(group, 0);
        return 0;
    }
    if ((group->phase == PHASE_MIDGROUP) &&
            (group->file_id == ntohs(fileinfo->file_id))) {
        // We already got the FILEINFO, and it's for a completed file.
        // So resend the COMPLETE and reset the timeout
        send_complete(group, (fileinfo->ftype == FTYPE_FREESPACE));
        set_timeout(group, 0);
        return 0;
    }

    // Load fileinfo params into list
    memset(&group->fileinfo, 0, sizeof(struct file_t));
    group->fileinfo.ftype = fileinfo->ftype;
    group->file_id = ntohs(fileinfo->file_id);
    strncpy(group->fileinfo.name, name, fileinfo->namelen * 4);
    strncpy(group->fileinfo.linkname, flink, fileinfo->linklen * 4);
    group->fileinfo.size = (f_offset_t)ntohs(fileinfo->hifsize) << 32;
    group->fileinfo.size |= ntohl(fileinfo->lofsize);

    if (group->fileinfo.size) {
        maxsecsize = (group->blocksize * 8 > MAXSECTION ?
                MAXSECTION : group->blocksize * 8);
        group->fileinfo.blocks =
                (int32_t)((group->fileinfo.size / group->blocksize) +
                (group->fileinfo.size % group->blocksize ? 1 : 0));
        group->fileinfo.sections = (group->fileinfo.blocks / maxsecsize) +
                (group->fileinfo.blocks % maxsecsize ? 1 : 0);
        group->fileinfo.secsize_small =
                group->fileinfo.blocks / group->fileinfo.sections;
        group->fileinfo.secsize_big = group->fileinfo.secsize_small +
                (group->fileinfo.blocks % group->fileinfo.sections ? 1 : 0);
        group->fileinfo.big_sections = group->fileinfo.blocks -
                (group->fileinfo.secsize_small * group->fileinfo.sections);
    } else {
        group->fileinfo.blocks = 0;
        group->fileinfo.sections = 0;
        group->fileinfo.secsize_small = 0;
        group->fileinfo.secsize_big = 0;
        group->fileinfo.big_sections = 0;
    }

    group->fileinfo.tstamp = ntohl(fileinfo->ftstamp);
    group->last_server_ts.tv_sec = ntohl(fileinfo->tstamp_sec);
    group->last_server_ts.tv_usec = ntohl(fileinfo->tstamp_usec);
    group->last_server_rx_ts = rxtime;
    group->fileinfo.fd = -1;

    // Run some checks on the filename
    if (strlen(group->fileinfo.name) == 0) {
        glog1(group, "Rejecting FILEINFO from server: blank file name");
        early_complete(group, COMP_STAT_REJECTED, 0);
        return 0;
    }
    p = strstr(group->fileinfo.name, "..");
    if ((p != NULL) && ((p[2] == '\x0') || (p[2] == '/') || (p[2] == '\\')) &&
           ((p == group->fileinfo.name) || (p[-1] == '/') || (p[-1] == '\\'))) {
        glog1(group, "Rejecting FILEINFO from server: filename contains ..");
        early_complete(group, COMP_STAT_REJECTED, 0);
        return 0;
    }
    if (fileinfo->ftype == FTYPE_LINK) {
        if (strlen(group->fileinfo.linkname) == 0) {
            glog1(group, "Rejecting FILEINFO from server: blank link name");
            early_complete(group, COMP_STAT_REJECTED, 0);
            return 0;
        }
    }

    return 1;
}
Ejemplo n.º 9
0
static int
send_diffs (krb5_context context, slave *s, int log_fd,
	    const char *database, u_int32_t current_version)
{
    krb5_storage *sp;
    u_int32_t ver;
    time_t timestamp;
    enum kadm_ops op;
    u_int32_t len;
    off_t right, left;
    krb5_data data;
    int ret = 0;

    if (s->version == current_version)
	return 0;

    if (s->flags & SLAVE_F_DEAD)
	return 0;

    sp = kadm5_log_goto_end (log_fd);
    right = krb5_storage_seek(sp, 0, SEEK_CUR);
    for (;;) {
	if (kadm5_log_previous (sp, &ver, &timestamp, &op, &len))
	    abort ();
	left = krb5_storage_seek(sp, -16, SEEK_CUR);
	if (ver == s->version)
	    return 0;
	if (ver == s->version + 1)
	    break;
	if (left == 0)
	    return send_complete (context, s, database, current_version);
    }
    ret = krb5_data_alloc (&data, right - left + 4);
    if (ret) {
	krb5_warn (context, ret, "send_diffs: krb5_data_alloc");
	slave_dead(s);
	return 1;
    }
    krb5_storage_read (sp, (char *)data.data + 4, data.length - 4);
    krb5_storage_free(sp);

    sp = krb5_storage_from_data (&data);
    if (sp == NULL) {
	krb5_warnx (context, "send_diffs: krb5_storage_from_data");
	slave_dead(s);
	return 1;
    }
    krb5_store_int32 (sp, FOR_YOU);
    krb5_storage_free(sp);

    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
    krb5_data_free(&data);

    if (ret) {
	krb5_warn (context, ret, "send_diffs: krb5_write_priv_message");
	slave_dead(s);
	return 1;
    }
    slave_seen(s);

    return 0;
}
Ejemplo n.º 10
0
static int
send_diffs (kadm5_server_context *server_context, slave *s, int log_fd,
	    const char *database, uint32_t current_version,
	    uint32_t current_tstamp)
{
    krb5_context context = server_context->context;
    krb5_storage *sp;
    uint32_t ver, initial_version, initial_version2;
    uint32_t initial_tstamp, initial_tstamp2;
    enum kadm_ops op;
    uint32_t len;
    off_t right, left;
    krb5_ssize_t bytes;
    krb5_data data;
    int ret = 0;

    if (s->flags & SLAVE_F_DEAD) {
        krb5_warnx(context, "not sending diffs to dead slave %s", s->name);
        return 0;
    }

    if (s->version == current_version) {
	char buf[4];

	sp = krb5_storage_from_mem(buf, 4);
	if (sp == NULL)
	    krb5_errx(context, IPROPD_RESTART, "krb5_storage_from_mem");
	ret = krb5_store_uint32(sp, YOU_HAVE_LAST_VERSION);
	krb5_storage_free(sp);
	data.data   = buf;
	data.length = 4;
        if (ret == 0) {
            ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
            if (ret) {
                krb5_warn(context, ret, "send_diffs: failed to send to slave");
                slave_dead(context, s);
            }
            krb5_warnx(context, "slave %s in sync already at version %ld",
                       s->name, (long)s->version);
        }
	return ret;
    }

    if (verbose)
        krb5_warnx(context, "sending diffs to live-seeming slave %s", s->name);

    /*
     * XXX The code that makes the diffs should be made a separate function,
     * then error handling (send_are_you_there() or slave_dead()) can be done
     * here.
     */

    if (flock(log_fd, LOCK_SH) == -1) {
        krb5_warn(context, errno, "could not obtain shared lock on log file");
        send_are_you_there(context, s);
        return errno;
    }
    ret = kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_FIRST,
                                   &initial_version, &initial_tstamp);
    sp = kadm5_log_goto_end(server_context, log_fd);
    flock(log_fd, LOCK_UN);
    if (ret) {
        if (sp != NULL)
            krb5_storage_free(sp);
        krb5_warn(context, ret, "send_diffs: failed to read log");
        send_are_you_there(context, s);
        return ret;
    }
    if (sp == NULL) {
        send_are_you_there(context, s);
        krb5_warn(context, errno ? errno : EINVAL,
                  "send_diffs: failed to read log");
        return errno ? errno : EINVAL;
    }
    /*
     * We're not holding any locks here, so we can't prevent truncations.
     *
     * We protect against this by re-checking that the initial version and
     * timestamp are the same before and after this loop.
     */
    right = krb5_storage_seek(sp, 0, SEEK_CUR);
    if (right == (off_t)-1) {
        krb5_storage_free(sp);
        send_are_you_there(context, s);
        return errno;
    }
    for (;;) {
	ret = kadm5_log_previous (context, sp, &ver, NULL, &op, &len);
	if (ret)
	    krb5_err(context, IPROPD_RESTART, ret,
		     "send_diffs: failed to find previous entry");
	left = krb5_storage_seek(sp, -16, SEEK_CUR);
        if (left == (off_t)-1) {
            krb5_storage_free(sp);
            send_are_you_there(context, s);
            return errno;
        }
	if (ver == s->version + 1)
	    break;

        /*
         * We don't expect to reach the slave's version, except when it is
         * starting empty with the uber record.
         */
	if (ver == s->version && !(ver == 0 && op == kadm_nop)) {
            /*
             * This shouldn't happen, but recall we're not holding a lock on
             * the log.
             */
            krb5_storage_free(sp);
            krb5_warnx(context, "iprop log truncated while sending diffs to "
                       "slave??  ver = %lu", (unsigned long)ver);
            send_are_you_there(context, s);
            return 0;
        }

        /* If we've reached the uber record, send the complete database */
	if (left == 0 || (ver == 0 && op == kadm_nop)) {
	    krb5_storage_free(sp);
	    krb5_warnx(context,
		       "slave %s (version %lu) out of sync with master "
		       "(first version in log %lu), sending complete database",
		       s->name, (unsigned long)s->version, (unsigned long)ver);
	    return send_complete (context, s, database, current_version, ver,
                                  initial_tstamp);
	}
    }

    assert(ver == s->version + 1);

    krb5_warnx(context,
	       "syncing slave %s from version %lu to version %lu",
	       s->name, (unsigned long)s->version,
	       (unsigned long)current_version);

    ret = krb5_data_alloc (&data, right - left + 4);
    if (ret) {
	krb5_storage_free(sp);
	krb5_warn (context, ret, "send_diffs: krb5_data_alloc");
        send_are_you_there(context, s);
	return 1;
    }
    bytes = krb5_storage_read(sp, (char *)data.data + 4, data.length - 4);
    krb5_storage_free(sp);
    if (bytes != data.length - 4) {
        krb5_warnx(context, "iprop log truncated while sending diffs to "
                   "slave??  ver = %lu", (unsigned long)ver);
        send_are_you_there(context, s);
        return 1;
    }

    /*
     * Check that we have the same log initial version and timestamp now as
     * when we dropped the shared lock on the log file!  Else we could be
     * sending garbage to the slave.
     */
    if (flock(log_fd, LOCK_SH) == -1) {
        krb5_warn(context, errno, "could not obtain shared lock on log file");
        send_are_you_there(context, s);
        return 1;
    }
    ret = kadm5_log_get_version_fd(server_context, log_fd, LOG_VERSION_FIRST,
                                   &initial_version2, &initial_tstamp2);
    flock(log_fd, LOCK_UN);
    if (ret) {
        krb5_warn(context, ret,
                   "send_diffs: failed to read log while producing diffs");
        send_are_you_there(context, s);
        return 1;
    }
    if (initial_version != initial_version2 ||
        initial_tstamp != initial_tstamp2) {
        krb5_warn(context, ret,
                   "send_diffs: log truncated while producing diffs");
        send_are_you_there(context, s);
        return 1;
    }

    sp = krb5_storage_from_data (&data);
    if (sp == NULL) {
	krb5_warnx (context, "send_diffs: krb5_storage_from_data");
        send_are_you_there(context, s);
	return 1;
    }
    krb5_store_uint32 (sp, FOR_YOU);
    krb5_storage_free(sp);

    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
    krb5_data_free(&data);

    if (ret) {
	krb5_warn (context, ret, "send_diffs: krb5_write_priv_message");
	slave_dead(context, s);
	return 1;
    }
    slave_seen(s);

    s->version = current_version;

    krb5_warnx(context, "slave %s is now up to date (%u)", s->name, s->version);

    return 0;
}
Ejemplo n.º 11
0
/**
 * Gets the current timeout value to use for the main loop
 *
 * First check to see if any active groups have an expired timeout, and
 * handle that timeout.  Once all expired timeouts have been handled, find
 * the active group with the earliest timeout and return the time until that
 * timeout.  If there are no active groups, return NULL.
 */
struct timeval *getrecenttimeout(void)
{
    static struct timeval tv = {0,0};
    struct timeval current_timestamp, min_timestamp;
    int i, found_timeout, done, sent_naks;
    struct group_list_t *group;
    unsigned int section, nak_count;
    unsigned char *naks;

    gettimeofday(&current_timestamp, NULL);
    done = 0;
    while (!done) {
        found_timeout = 0;
        done = 1;
        for (i = 0; i < MAXLIST; i++) {
            group = &group_list[i];
            if (group->group_id != 0) {
                if (cmptimestamp(current_timestamp, group->timeout_time) >= 0) {
                    switch (group->phase) {
                    case PHASE_REGISTERED:
                        send_register(group);
                        break;
                    case PHASE_RECEIVING:
                    case PHASE_MIDGROUP:
                        glog1(group, "Transfer timed out");
                        send_abort(group, "Transfer timed out");
                        break;
                    case PHASE_COMPLETE:
                        send_complete(group, 0);
                        break;
                    }
                    done = 0;
                } else if ((!found_timeout) ||
                           (cmptimestamp(group->timeout_time,
                                         min_timestamp) < 0)) {
                    glog5(group, "found min timeout time: %d:%06d",
                                 group->timeout_time.tv_sec,
                                 group->timeout_time.tv_usec);
                    min_timestamp = group->timeout_time;
                    found_timeout = 1;
                }
                // Check for a NAK timeout for sending a STATUS or COMPLETE
                if ((group->fileinfo.nak_time.tv_sec != 0) &&
                        cmptimestamp(current_timestamp,
                                     group->fileinfo.nak_time) >= 0) {
                    group->fileinfo.nak_time.tv_sec = 0;
                    group->fileinfo.nak_time.tv_usec = 0;
                    // Send NAKs
                    sent_naks = 0;
                retry_naks:
                    for (section = group->fileinfo.nak_section_first;
                            section < group->fileinfo.nak_section_last;
                            section++) {
                        naks = NULL;
                        nak_count = get_naks(group, section, &naks);
                        glog3(group, "read %d NAKs for section %d",
                                     nak_count, section);
                        if (nak_count > 0) {
                            send_status(group, section, naks, nak_count);
                            sent_naks = 1;
                        }
                        free(naks);
                        naks = NULL;
                    }
                    if (file_done(group, 1)) {
                        glog2(group, "File transfer complete");
                        send_complete(group, 0);
                        file_cleanup(group, 0);
                    } else if (group->fileinfo.got_done && !sent_naks) {
                        // We didn't send any NAKs since the last time
                        // but the server is asking for some,
                        // so check all prior sections
                        group->fileinfo.nak_section_last = 
                                group->fileinfo.nak_section_first;
                        group->fileinfo.nak_section_first = 0;
                        group->fileinfo.got_done = 0;
                        goto retry_naks;
                    }
                } else if ((group->fileinfo.nak_time.tv_sec != 0) &&
                           ((!found_timeout) ||
                            (cmptimestamp(group->fileinfo.nak_time,
                                          min_timestamp) < 0))) {
                    glog5(group, "found min nak time: %d:%06d",
                         group->fileinfo.nak_time.tv_sec,
                         group->fileinfo.nak_time.tv_usec);
                    min_timestamp = group->fileinfo.nak_time;
                    found_timeout = 1;
                }
                // Check congestion control feedback timer
                if (!group->isclr) {
                    if ((group->cc_time.tv_sec != 0) &&
                            (cmptimestamp(current_timestamp,
                                          group->cc_time) >= 0)) {
                        send_cc_ack(group);
                    } else if ((group->cc_time.tv_sec != 0) &&
                               ((!found_timeout) ||
                                (cmptimestamp(group->cc_time,
                                              min_timestamp) < 0))) {
                        glog5(group, "found min CC time: %d:%06d",
                             group->cc_time.tv_sec, group->cc_time.tv_usec);
                        min_timestamp = group->cc_time;
                        found_timeout = 1;
                    }
                }
            }
        }
        // Check timeout for proxy key request
        if (has_proxy && (proxy_pubkey.key == 0)) {
            if (cmptimestamp(current_timestamp, next_keyreq_time) >= 0) {
                send_key_req();
                done = 0;
            } else if ((!found_timeout) ||
                       (cmptimestamp(next_keyreq_time, min_timestamp) < 0)) {
                min_timestamp = next_keyreq_time;
                found_timeout = 1;
            }
        }
        // Check timeout for sending heartbeat
        if (hbhost_count) {
            if (cmptimestamp(current_timestamp, next_hb_time) >= 0) {
                send_hb_request(listener, hb_hosts, hbhost_count,
                                &next_hb_time, hb_interval, uid);
                done = 0;
            } else if ((!found_timeout) ||
                       (cmptimestamp(next_hb_time, min_timestamp) < 0)) {
                min_timestamp = next_hb_time;
                found_timeout = 1;
            }
        }

    }
    if (found_timeout) {
        tv = diff_timeval(min_timestamp, current_timestamp);
        return &tv;
    } else {
        return NULL;
    }
}
Ejemplo n.º 12
0
/**
 * Gets the current timeout value to use for the main loop
 *
 * First check to see if any active groups have an expired timeout, and
 * handle that timeout.  Once all expired timeouts have been handled, find
 * the active group with the earliest timeout and return the time until that
 * timeout.  If there are no active groups, return NULL.
 */
struct timeval *getrecenttimeout()
{
    static struct timeval tv = {0,0};
    struct timeval current_timestamp, min_timestamp;
    int i, found_timeout, done;
    int32_t usecs;

    gettimeofday(&current_timestamp, NULL);
    done = 0;
    while (!done) {
        found_timeout = 0;
        done = 1;
        for (i = 0; i < MAXLIST; i++) {
            if (group_list[i].group_id != 0) {
                if (cmptimestamp(current_timestamp,
                                 group_list[i].timeout_time) >= 0) {
                    switch (group_list[i].phase) {
                    case PHASE_REGISTERED:
                        send_register(i);
                        break;
                    case PHASE_RECEIVING:
                    case PHASE_MIDGROUP:
                        log1(group_list[i].group_id, group_list[i].file_id,
                            "Transfer timed out");
                        send_abort(i, "Transfer timed out");
                        break;
                    case PHASE_COMPLETE:
                        send_complete(i);
                        break;
                    }
                    done = 0;
                } else if (!found_timeout) {
                    min_timestamp = group_list[i].timeout_time;
                    found_timeout = 1;
                } else if (cmptimestamp(group_list[i].timeout_time,
                                        min_timestamp) < 0) {
                    min_timestamp = group_list[i].timeout_time;
                }
            }
        }
        // Check timeout for proxy key request
        if (has_proxy && (proxy_key == (RSA_key_t)NULL)) {
            if (cmptimestamp(current_timestamp, next_keyreq_time) >= 0) {
                send_key_req();
                done = 0;
            } else if ((!found_timeout) ||
                       (cmptimestamp(next_keyreq_time, min_timestamp) < 0)) {
                min_timestamp = next_keyreq_time;
                found_timeout = 1;
            }
        }
        // Check timeout for sending heartbeat
        if (hbhost_count) {
            if (cmptimestamp(current_timestamp, next_hb_time) >= 0) {
                send_hb_request(listener, hb_hosts, hbhost_count,
                                &next_hb_time, hb_interval);
                done = 0;
            } else if ((!found_timeout) ||
                       (cmptimestamp(next_hb_time, min_timestamp) < 0)) {
                min_timestamp = next_hb_time;
                found_timeout = 1;
            }
        }

    }
    if (found_timeout) {
        usecs = (int32_t)diff_usec(min_timestamp, current_timestamp);
        tv.tv_sec = usecs / 1000000;
        tv.tv_usec = usecs % 1000000;
        return &tv;
    } else {
        return NULL;
    }
}
Ejemplo n.º 13
0
static int
send_diffs (krb5_context context, slave *s, int log_fd,
	    const char *database, uint32_t current_version)
{
    krb5_storage *sp;
    uint32_t ver;
    time_t timestamp;
    enum kadm_ops op;
    uint32_t len;
    off_t right, left;
    krb5_data data;
    int ret = 0;

    if (s->version == current_version) {
	krb5_warnx(context, "slave %s in sync already at version %ld",
		   s->name, (long)s->version);
	return 0;
    }

    if (s->flags & SLAVE_F_DEAD)
	return 0;

    /* if slave is a fresh client, starting over */
    if (s->version == 0) {
	krb5_warnx(context, "sending complete log to fresh slave %s",
		   s->name);
	return send_complete (context, s, database, current_version);
    }

    sp = kadm5_log_goto_end (log_fd);
    right = krb5_storage_seek(sp, 0, SEEK_CUR);
    for (;;) {
	ret = kadm5_log_previous (context, sp, &ver, &timestamp, &op, &len);
	if (ret)
	    krb5_err(context, 1, ret,
		     "send_diffs: failed to find previous entry");
	left = krb5_storage_seek(sp, -16, SEEK_CUR);
	if (ver == s->version)
	    return 0;
	if (ver == s->version + 1)
	    break;
	if (left == 0) {
	    krb5_storage_free(sp);
	    krb5_warnx(context,
		       "slave %s (version %lu) out of sync with master "
		       "(first version in log %lu), sending complete database",
		       s->name, (unsigned long)s->version, (unsigned long)ver);
	    return send_complete (context, s, database, current_version);
	}
    }

    krb5_warnx(context,
	       "syncing slave %s from version %lu to version %lu",
	       s->name, (unsigned long)s->version,
	       (unsigned long)current_version);

    ret = krb5_data_alloc (&data, right - left + 4);
    if (ret) {
	krb5_storage_free(sp);
	krb5_warn (context, ret, "send_diffs: krb5_data_alloc");
	slave_dead(context, s);
	return 1;
    }
    krb5_storage_read (sp, (char *)data.data + 4, data.length - 4);
    krb5_storage_free(sp);

    sp = krb5_storage_from_data (&data);
    if (sp == NULL) {
	krb5_warnx (context, "send_diffs: krb5_storage_from_data");
	slave_dead(context, s);
	return 1;
    }
    krb5_store_int32 (sp, FOR_YOU);
    krb5_storage_free(sp);

    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
    krb5_data_free(&data);

    if (ret) {
	krb5_warn (context, ret, "send_diffs: krb5_write_priv_message");
	slave_dead(context, s);
	return 1;
    }
    slave_seen(s);

    s->version = current_version;

    return 0;
}