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); } }
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); }
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); }
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); }