/** \brief connect to the indicated local stream socket, logging any errors
* \param path filesystem path to connect to
+ * \param log_err, non-zero if connect failure should be logged.
* \retval FILE* on success (fdopen'd wrapper of underlying socket)
* \retval NULL on error
*/
static FILE *
-SCLogOpenUnixSocketFp(const char *path, int sock_type)
+SCLogOpenUnixSocketFp(const char *path, int sock_type, int log_err)
{
struct sockaddr_un sun;
int s = -1;
return ret;
err:
- SCLogError(SC_ERR_SOCKET, "Error connecting to socket \"%s\": %s",
- path, strerror(errno));
+ if (log_err)
+ SCLogWarning(SC_ERR_SOCKET,
+ "Error connecting to socket \"%s\": %s (will keep trying)",
+ path, strerror(errno));
if (s >= 0)
close(s);
return NULL;
}
+/**
+ * \brief Attempt to reconnect a disconnected (or never-connected) Unix domain socket.
+ * \retval 1 if it is now connected; otherwise 0
+ */
+static int SCLogUnixSocketReconnect(LogFileCtx *log_ctx)
+{
+ int disconnected = 0;
+ if (log_ctx->fp) {
+ SCLogWarning(SC_ERR_SOCKET,
+ "Write error on Unix socket \"%s\": %s; reconnecting...",
+ log_ctx->filename, strerror(errno));
+ fclose(log_ctx->fp);
+ log_ctx->fp = NULL;
+ log_ctx->reconn_timer = 0;
+ disconnected = 1;
+ }
+
+ struct timeval tv;
+ uint64_t now;
+ gettimeofday(&tv, NULL);
+ now = (uint64_t)tv.tv_sec * 1000;
+ now += tv.tv_usec / 1000; /* msec resolution */
+ if (log_ctx->reconn_timer != 0 &&
+ (now - log_ctx->reconn_timer) < LOGFILE_RECONN_MIN_TIME) {
+ /* Don't bother to try reconnecting too often. */
+ return 0;
+ }
+ log_ctx->reconn_timer = now;
+
+ log_ctx->fp = SCLogOpenUnixSocketFp(log_ctx->filename, log_ctx->sock_type, 0);
+ if (log_ctx->fp) {
+ /* Connected at last (or reconnected) */
+ SCLogNotice("Reconnected socket \"%s\"", log_ctx->filename);
+ } else if (disconnected) {
+ SCLogWarning(SC_ERR_SOCKET, "Reconnect failed: %s (will keep trying)",
+ strerror(errno));
+ }
+
+ return log_ctx->fp ? 1 : 0;
+}
+
+/**
+ * \brief Write buffer to log file.
+ * \retval 0 on failure; otherwise, the return value of fwrite (number of
+ * characters successfully written).
+ */
static int SCLogFileWrite(const char *buffer, int buffer_len, LogFileCtx *log_ctx)
{
/* Check for rotation. */
int ret = 0;
+ if (log_ctx->fp == NULL && log_ctx->is_sock)
+ SCLogUnixSocketReconnect(log_ctx);
+
if (log_ctx->fp) {
+ clearerr(log_ctx->fp);
ret = fwrite(buffer, buffer_len, 1, log_ctx->fp);
fflush(log_ctx->fp);
+
+ if (ferror(log_ctx->fp) && log_ctx->is_sock) {
+ /* Error on Unix socket, maybe needs reconnect */
+ if (SCLogUnixSocketReconnect(log_ctx)) {
+ ret = fwrite(buffer, buffer_len, 1, log_ctx->fp);
+ fflush(log_ctx->fp);
+ }
+ }
}
return ret;
// Now, what have we been asked to open?
if (strcasecmp(filetype, "unix_stream") == 0) {
- log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM);
- if (log_ctx->fp == NULL)
- return -1; // Error already logged by Open...Fp routine
+ /* Don't bail. May be able to connect later. */
+ log_ctx->is_sock = 1;
+ log_ctx->sock_type = SOCK_STREAM;
+ log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1);
} else if (strcasecmp(filetype, "unix_dgram") == 0) {
- log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM);
- if (log_ctx->fp == NULL)
- return -1; // Error already logged by Open...Fp routine
+ /* Don't bail. May be able to connect later. */
+ log_ctx->is_sock = 1;
+ log_ctx->sock_type = SOCK_DGRAM;
+ log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1);
} else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 ||
strcasecmp(filetype, "file") == 0) {
log_ctx->fp = SCLogOpenFileFp(log_path, append);
if (log_ctx->fp == NULL)
return -1; // Error already logged by Open...Fp routine
log_ctx->is_regular = 1;
- log_ctx->filename = SCStrdup(log_path);
- if (unlikely(log_ctx->filename == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for "
- "filename");
- return -1;
- }
if (rotate) {
OutputRegisterFileRotationFlag(&log_ctx->rotation_flag);
}
"or \"unix_dgram\"",
conf->name);
}
+ log_ctx->filename = SCStrdup(log_path);
+ if (unlikely(log_ctx->filename == NULL)) {
+ SCLogError(SC_ERR_MEM_ALLOC,
+ "Failed to allocate memory for filename");
+ return -1;
+ }
SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype,
filename);