Files
CS-LABS/kirill/rgz/daemon.c
2025-12-17 15:49:17 +07:00

195 lines
6.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// fifo_server_daemon.c
// Демон: читает из FIFO_REQUEST, обрабатывает текст,
// В КАЖДОЙ СТРОКЕ заменяет пробелом каждый 3-й байт, который НЕ '\n'.
// '\n' сохраняется и сбрасывает счётчик позиции внутри строки.
// Пишет результат в FIFO_RESPONSE и дописывает "\nREPLACEMENTS:<n>\n".
// Логирует ошибки в syslog, игнорирует SIGPIPE (чтобы write() не убивал процесс). [web:21][web:28]
#include <stdio.h> // fprintf, snprintf
#include <stdlib.h> // malloc, free, strtoll
#include <string.h> // strlen, strerror, memset
#include <unistd.h> // read, write, close, unlink
#include <fcntl.h> // open, O_RDONLY, O_WRONLY
#include <sys/types.h> // типы
#include <sys/stat.h> // mkfifo
#include <errno.h> // errno
#include <signal.h> // sigaction, SIGINT, SIGTERM, SIGPIPE
#include <syslog.h> // syslog, openlog, closelog
#define FIFO_REQUEST "/tmp/fifo_request"
#define FIFO_RESPONSE "/tmp/fifo_response"
#define BUFFER_SIZE 4096
static volatile sig_atomic_t running = 1;
static void signal_handler(int sig) {
(void) sig;
running = 0;
}
// разбор неотрицательного long long
static long long parse_ll(const char *s) {
char *end = NULL;
errno = 0;
long long v = strtoll(s, &end, 10);
if (errno != 0 || end == s || *end != '\0' || v < 0) return -1;
return v;
}
// В каждой строке: заменить каждый 3-й НЕ '\n' байт на пробел.
// Возвращает количество замен.
static long long process_data(const char *input, size_t input_len,
char *output, size_t output_size) {
if (!input || !output || input_len == 0 || output_size == 0) {
return 0;
}
long long replacements = 0;
size_t out_pos = 0;
size_t pos_in_line = 0; // считает только не-'\n' байты в текущей строке
for (size_t i = 0; i < input_len && out_pos < output_size - 1; i++) {
unsigned char c = (unsigned char) input[i];
if (c == '\n') {
output[out_pos++] = '\n';
pos_in_line = 0;
continue;
}
pos_in_line++;
if (pos_in_line % 3 == 0) {
output[out_pos++] = ' ';
replacements++;
} else {
output[out_pos++] = (char) c;
}
}
output[out_pos] = '\0';
return replacements;
}
int main(int argc, char *argv[]) {
// Аргумент оставлен для совместимости с вашим запуском, но больше не влияет на обработку.
if (argc != 2) {
fprintf(stderr, "Usage: %s <ignored_max_replacements>\n", argv[0]);
return 1;
}
long long ignored = parse_ll(argv[1]);
if (ignored < 0) {
fprintf(stderr, "ERROR: Invalid argument (must be non-negative integer)\n");
return 1;
}
openlog("fifo_server_daemon", LOG_PID | LOG_NDELAY, LOG_DAEMON);
syslog(LOG_INFO, "Server started (systemd), arg(ignored)=%lld", ignored); // syslog via openlog/syslog [web:28]
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
signal(SIGPIPE, SIG_IGN); // игнор SIGPIPE, обработка ошибок через write() [web:21]
unlink(FIFO_REQUEST);
unlink(FIFO_RESPONSE);
if (mkfifo(FIFO_REQUEST, 0666) == -1) {
syslog(LOG_ERR, "mkfifo request failed: %s", strerror(errno)); // mkfifo creates FIFO special file [web:37]
closelog();
return 1;
}
if (mkfifo(FIFO_RESPONSE, 0666) == -1) {
syslog(LOG_ERR, "mkfifo response failed: %s", strerror(errno)); // mkfifo creates FIFO special file [web:37]
unlink(FIFO_REQUEST);
closelog();
return 1;
}
syslog(LOG_INFO, "FIFO created: request=%s, response=%s", FIFO_REQUEST, FIFO_RESPONSE);
while (running) {
int fd_req = open(FIFO_REQUEST, O_RDONLY);
// open FIFO for reading can block until writer connects [web:26][web:35]
if (!running) {
if (fd_req != -1) close(fd_req);
break;
}
if (fd_req == -1) {
if (errno == EINTR) continue;
syslog(LOG_ERR, "open request FIFO failed: %s", strerror(errno));
break;
}
char *input_buffer = (char *) malloc(BUFFER_SIZE);
char *output_buffer = (char *) malloc(BUFFER_SIZE);
if (!input_buffer || !output_buffer) {
syslog(LOG_ERR, "Memory allocation failed");
close(fd_req);
free(input_buffer);
free(output_buffer);
break;
}
ssize_t bytes_read = read(fd_req, input_buffer, BUFFER_SIZE - 1);
close(fd_req);
if (!running) {
free(input_buffer);
free(output_buffer);
break;
}
if (bytes_read <= 0) {
free(input_buffer);
free(output_buffer);
if (!running) break;
continue;
}
input_buffer[bytes_read] = '\0';
syslog(LOG_INFO, "Request received: %zd bytes", bytes_read);
long long replacements =
process_data(input_buffer, (size_t) bytes_read, output_buffer, BUFFER_SIZE);
int fd_resp = open(FIFO_RESPONSE, O_WRONLY);
// open FIFO for writing can block until reader connects [web:26][web:35]
if (fd_resp == -1) {
syslog(LOG_ERR, "open response FIFO failed: %s", strerror(errno));
free(input_buffer);
free(output_buffer);
if (!running) break;
continue;
}
size_t output_len = strlen(output_buffer);
ssize_t bytes_written = write(fd_resp, output_buffer, output_len);
char trailer[64];
snprintf(trailer, sizeof(trailer), "\nREPLACEMENTS:%lld\n", replacements);
if (write(fd_resp, trailer, strlen(trailer)) < 0) {
syslog(LOG_WARNING, "write replacements trailer failed: %s", strerror(errno));
}
close(fd_resp);
syslog(LOG_INFO, "Response sent: %zd bytes; replacements=%lld",
bytes_written, replacements);
free(input_buffer);
free(output_buffer);
}
syslog(LOG_INFO, "Server stopping, cleaning up");
unlink(FIFO_REQUEST);
unlink(FIFO_RESPONSE);
closelog();
return 0;
}