Files
nginx-unit/src/nxt_go.c
Max Romanov 799cff5f3e Introducing Unit version check in Go package.
To communicate with the Go program, Unit setup environment variable
named NXT_GO_PORTS with value contains Unit version, stream id to confirm
application is started, and Unit ports information.  Go Unit package parses
this string and compares runtime version with compile time version.  In case
of parse error or version mismatch, ListenAndServe() returns with the error.
2017-12-13 18:12:13 +03:00

138 lines
3.1 KiB
C

/*
* Copyright (C) Max Romanov
* Copyright (C) NGINX, Inc.
*/
#include <nxt_main.h>
#include <nxt_application.h>
static nxt_int_t nxt_go_init(nxt_task_t *task, nxt_common_app_conf_t *conf);
static nxt_int_t nxt_go_run(nxt_task_t *task,
nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *msg);
nxt_application_module_t nxt_go_module = {
0,
NULL,
nxt_string("go"),
nxt_string("go"),
nxt_go_init,
nxt_go_run,
};
extern char **environ;
nxt_inline nxt_int_t
nxt_go_fd_no_cloexec(nxt_task_t *task, nxt_socket_t fd)
{
int res, flags;
if (fd == -1) {
return NXT_OK;
}
flags = fcntl(fd, F_GETFD);
if (nxt_slow_path(flags == -1)) {
nxt_log(task, NXT_LOG_CRIT, "fcntl(%d, F_GETFD) failed %E",
fd, nxt_errno);
return NXT_ERROR;
}
flags &= ~FD_CLOEXEC;
res = fcntl(fd, F_SETFD, flags);
if (nxt_slow_path(res == -1)) {
nxt_log(task, NXT_LOG_CRIT, "fcntl(%d, F_SETFD) failed %E",
fd, nxt_errno);
return NXT_ERROR;
}
return NXT_OK;
}
static nxt_int_t
nxt_go_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
{
char *argv[2];
u_char buf[256];
u_char *p, *end;
nxt_int_t rc;
nxt_port_t *my_port, *main_port;
nxt_runtime_t *rt;
nxt_go_app_conf_t *c;
rt = task->thread->runtime;
main_port = rt->port_by_type[NXT_PROCESS_MAIN];
my_port = nxt_runtime_port_find(rt, nxt_pid, 0);
if (nxt_slow_path(main_port == NULL || my_port == NULL)) {
return NXT_ERROR;
}
rc = nxt_go_fd_no_cloexec(task, main_port->pair[1]);
if (nxt_slow_path(rc != NXT_OK)) {
return NXT_ERROR;
}
rc = nxt_go_fd_no_cloexec(task, my_port->pair[0]);
if (nxt_slow_path(rc != NXT_OK)) {
return NXT_ERROR;
}
end = buf + sizeof(buf);
p = nxt_sprintf(buf, end,
"%s;%uD;"
"%PI,%ud,%d,%d,%d;"
"%PI,%ud,%d,%d,%d%Z",
NXT_VERSION, my_port->process->init->stream,
main_port->pid, main_port->id, (int) main_port->type,
-1, main_port->pair[1],
my_port->pid, my_port->id, (int) my_port->type,
my_port->pair[0], -1);
if (nxt_slow_path(p == end)) {
nxt_log(task, NXT_LOG_ALERT,
"internal error: buffer too small for NXT_GO_PORTS");
return NXT_ERROR;
}
nxt_debug(task, "update NXT_GO_PORTS=%s", buf);
rc = setenv("NXT_GO_PORTS", (char *) buf, 1);
if (nxt_slow_path(rc == -1)) {
nxt_log(task, NXT_LOG_CRIT, "setenv(NXT_GO_PORTS, %s) failed %E",
buf, nxt_errno);
return NXT_ERROR;
}
c = &conf->u.go;
argv[0] = c->executable;
argv[1] = NULL;
(void) execve(c->executable, argv, environ);
nxt_log(task, NXT_LOG_CRIT, "execve(%s) failed %E",
c->executable, nxt_errno);
return NXT_ERROR;
}
static nxt_int_t
nxt_go_run(nxt_task_t *task,
nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *msg)
{
return NXT_ERROR;
}