示例#1
0
static void connect_event(int unused_event, void *context)
{
    int     sock = CAST_ANY_PTR_TO_INT(context);
    struct sockaddr_storage ss;
    SOCKADDR_SIZE len = sizeof(ss);
    struct sockaddr *sa = (struct sockaddr *) &ss;
    SINK_STATE *state;
    int     fd;

    if ((fd = accept(sock, sa, &len)) >= 0) {
	if (msg_verbose)
	    msg_info("connect (%s)",
#ifdef AF_LOCAL
		     sa->sa_family == AF_LOCAL ? "AF_LOCAL" :
#else
		     sa->sa_family == AF_UNIX ? "AF_UNIX" :
#endif
		     sa->sa_family == AF_INET ? "AF_INET" :
#ifdef AF_INET6
		     sa->sa_family == AF_INET6 ? "AF_INET6" :
#endif
		     "unknown protocol family");
	non_blocking(fd, NON_BLOCKING);
	state = (SINK_STATE *) mymalloc(sizeof(*state));
	state->stream = vstream_fdopen(fd, O_RDWR);
	vstream_tweak_sock(state->stream);
	netstring_setup(state->stream, var_tmout);
	event_enable_read(fd, read_length, (void *) state);
    }
}
示例#2
0
static void start_connect(SESSION *session)
{
    int     fd;
    struct linger linger;

    /*
     * Some systems don't set the socket error when connect() fails early
     * (loopback) so we must deal with the error immediately, rather than
     * retrieving it later with getsockopt(). We can't use MSG_PEEK to
     * distinguish between server disconnect and connection refused.
     */
    if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
	msg_fatal("socket: %m");
    (void) non_blocking(fd, NON_BLOCKING);
    linger.l_onoff = 1;
    linger.l_linger = 0;
    if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &linger,
		   sizeof(linger)) < 0)
	msg_warn("setsockopt SO_LINGER %d: %m", linger.l_linger);
    session->stream = vstream_fdopen(fd, O_RDWR);
    event_enable_write(fd, connect_done, (char *) session);
    netstring_setup(session->stream, var_timeout);
    if (sane_connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS)
	fail_connect(session);
}
示例#3
0
static void qmqpd_proto(QMQPD_STATE *state)
{
    int     status;

    netstring_setup(state->client, var_qmqpd_timeout);

    switch (status = vstream_setjmp(state->client)) {

    default:
	msg_panic("qmqpd_proto: unknown status %d", status);

    case NETSTRING_ERR_EOF:
	state->reason = "lost connection";
	break;

    case NETSTRING_ERR_TIME:
	state->reason = "read/write timeout";
	break;

    case NETSTRING_ERR_FORMAT:
	state->reason = "netstring format error";
	if (vstream_setjmp(state->client) == 0)
	    if (state->reason && state->where)
		qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s",
			    state->reason, state->where);
	break;

    case NETSTRING_ERR_SIZE:
	state->reason = "netstring length exceeds storage limit";
	if (vstream_setjmp(state->client) == 0)
	    if (state->reason && state->where)
		qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s",
			    state->reason, state->where);
	break;

    case 0:

	/*
	 * See if we want to talk to this client at all.
	 */
	if (namadr_list_match(qmqpd_clients, state->name, state->addr) != 0) {
	    qmqpd_receive(state);
	} else if (qmqpd_clients->error == 0) {
	    qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD,
			"Error: %s is not authorized to use this service",
			state->namaddr);
	} else {
	    qmqpd_reply(state, DONT_LOG, QMQPD_STAT_RETRY,
			"Error: server configuration error");
	}
	break;
    }

    /*
     * Log abnormal session termination. Indicate the last recognized state
     * before things went wrong.
     */
    if (state->reason && state->where)
	msg_info("%s: %s: %s while %s",
	      state->queue_id, state->namaddr, state->reason, state->where);
}
示例#4
0
static const char *dict_sockmap_lookup(DICT *dict, const char *key)
{
    const char *myname = "dict_sockmap_lookup";
    DICT_SOCKMAP *dp = (DICT_SOCKMAP *) dict;
    AUTO_CLNT *sockmap_clnt = DICT_SOCKMAP_RH_HANDLE(dp->client_info);
    VSTREAM *fp;
    int     netstring_err;
    char   *reply_payload;
    int     except_count;
    const char *error_class;

    if (msg_verbose)
	msg_info("%s: key %s", myname, key);

    /*
     * Optionally fold the key.
     */
    if (dict->flags & DICT_FLAG_FOLD_MUL) {
	if (dict->fold_buf == 0)
	    dict->fold_buf = vstring_alloc(100);
	vstring_strcpy(dict->fold_buf, key);
	key = lowercase(STR(dict->fold_buf));
    }

    /*
     * We retry connection-level errors once, to make server restarts
     * transparent.
     */
    for (except_count = 0; /* see below */ ; except_count++) {

	/*
	 * Look up the stream.
	 */
	if ((fp = auto_clnt_access(sockmap_clnt)) == 0) {
	    msg_warn("table %s:%s lookup error: %m", dict->type, dict->name);
	    dict->error = DICT_ERR_RETRY;
	    return (0);
	}

	/*
	 * Set up an exception handler.
	 */
	netstring_setup(fp, dict_sockmap_timeout);
	if ((netstring_err = vstream_setjmp(fp)) == 0) {

	    /*
	     * Send the query. This may raise an exception.
	     */
	    vstring_sprintf(dp->rdwr_buf, "%s %s", dp->sockmap_name, key);
	    NETSTRING_PUT_BUF(fp, dp->rdwr_buf);

	    /*
	     * Receive the response. This may raise an exception.
	     */
	    netstring_get(fp, dp->rdwr_buf, dict_sockmap_max_reply);

	    /*
	     * If we got here, then no exception was raised.
	     */
	    break;
	}

	/*
	 * Handle exceptions.
	 */
	else {

	    /*
	     * We retry a broken connection only once.
	     */
	    if (except_count == 0 && netstring_err == NETSTRING_ERR_EOF
		&& errno != ETIMEDOUT) {
		auto_clnt_recover(sockmap_clnt);
		continue;
	    }

	    /*
	     * We do not retry other errors.
	     */
	    else {
		msg_warn("table %s:%s lookup error: %s",
			 dict->type, dict->name,
			 netstring_strerror(netstring_err));
		dict->error = DICT_ERR_RETRY;
		return (0);
	    }
	}
    }

    /*
     * Parse the reply.
     */
    VSTRING_TERMINATE(dp->rdwr_buf);
    reply_payload = split_at(STR(dp->rdwr_buf), ' ');
    if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_OK) == 0) {
	dict->error = 0;
	return (reply_payload);
    } else if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_NOTFOUND) == 0) {
	dict->error = 0;
	return (0);
    }
    /* We got no definitive reply. */
    if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_TEMP) == 0) {
	error_class = "temporary";
	dict->error = DICT_ERR_RETRY;
    } else if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_TIMEOUT) == 0) {
	error_class = "timeout";
	dict->error = DICT_ERR_RETRY;
    } else if (strcmp(STR(dp->rdwr_buf), DICT_SOCKMAP_PROT_PERM) == 0) {
	error_class = "permanent";
	dict->error = DICT_ERR_CONFIG;
    } else {
	error_class = "unknown";
	dict->error = DICT_ERR_RETRY;
    }
    while (reply_payload && ISSPACE(*reply_payload))
	reply_payload++;
    msg_warn("%s:%s socketmap server %s error%s%.200s",
	     dict->type, dict->name, error_class,
	     reply_payload && *reply_payload ? ": " : "",
	     reply_payload && *reply_payload ?
	     printable(reply_payload, '?') : "");
    return (0);
}