-
Notifications
You must be signed in to change notification settings - Fork 369
Socket: replacement of called functions, permissions, reusability #670
Changes from all commits
31951d1
440ecaf
6e3f50e
25faad7
2d46b17
491fe57
2912b54
867d4ec
1497d19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ | |
|
|
||
|
|
||
| static u_char *nxt_listen_socket_log_handler(void *ctx, u_char *pos, | ||
| u_char *last); | ||
| u_char *end); | ||
|
|
||
|
|
||
| nxt_int_t | ||
|
|
@@ -35,11 +35,9 @@ nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp, | |
| nxt_socket_t s; | ||
| nxt_thread_t *thr; | ||
| nxt_sockaddr_t *sa; | ||
| nxt_err_t err; | ||
| #if (NXT_HAVE_UNIX_DOMAIN) | ||
| int ret; | ||
| u_char *p; | ||
| nxt_err_t err; | ||
| nxt_socket_t ts; | ||
| nxt_sockaddr_t *orig_sa; | ||
| nxt_file_name_t *name, *tmp; | ||
| nxt_file_access_t access; | ||
|
|
@@ -56,12 +54,29 @@ nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp, | |
|
|
||
| family = sa->u.sockaddr.sa_family; | ||
|
|
||
| s = nxt_socket_create(task, family, sa->type, 0, ls->flags); | ||
| s = nxt_socket_create(task, family, sa->type, 0, ls->flags, &err); | ||
| if (s == -1) { | ||
|
|
||
| #if (NXT_INET6) | ||
|
|
||
| if (err == EAFNOSUPPORT && sa->u.sockaddr.sa_family == AF_INET6) { | ||
| ls->error = NXT_SOCKET_ERROR_NOINET6; | ||
| } | ||
|
|
||
| #endif | ||
|
|
||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_socket_create(\"%*s\") failed %E", | ||
| (size_t) sa->length, nxt_sockaddr_start(sa), err); | ||
| goto fail; | ||
| } | ||
|
|
||
| if (nxt_socket_setsockopt(task, s, SOL_SOCKET, SO_REUSEADDR, 1) != NXT_OK) { | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_socket_setsockopt(\"%*s\", SO_REUSEADDR) failed", | ||
| (size_t) sa->length, nxt_sockaddr_start(sa)); | ||
| goto fail; | ||
| } | ||
|
|
||
|
|
@@ -72,9 +87,14 @@ nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp, | |
|
|
||
| ipv6only = (ls->ipv6only == 1); | ||
|
|
||
| /* Ignore possible error. TODO: why? */ | ||
| (void) nxt_socket_setsockopt(task, s, IPPROTO_IPV6, IPV6_V6ONLY, | ||
| ipv6only); | ||
| if (nxt_socket_setsockopt(task, s, IPPROTO_IPV6, IPV6_V6ONLY, | ||
| ipv6only) != NXT_OK) { | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_socket_setsockopt(\"%*s\", IPV6_V6ONLY) failed", | ||
| (size_t) sa->length, nxt_sockaddr_start(sa)); | ||
| goto fail; | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
|
|
@@ -100,6 +120,10 @@ nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp, | |
|
|
||
| sa = nxt_sockaddr_alloc(mp, sa->socklen + 4, sa->length + 4); | ||
| if (sa == NULL) { | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_sockaddr_alloc(%*s) failed", | ||
| (size_t) sa->length, nxt_sockaddr_start(sa)); | ||
| goto fail; | ||
| } | ||
|
|
||
|
|
@@ -108,84 +132,135 @@ nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp, | |
|
|
||
| p = nxt_cpystr((u_char *) sa->u.sockaddr_un.sun_path, | ||
| (u_char *) orig_sa->u.sockaddr_un.sun_path); | ||
| nxt_memcpy(p, ".tmp", 4); | ||
| nxt_memcpy(p, NXT_TMP_EXT, 4); | ||
|
|
||
| nxt_sockaddr_text(sa); | ||
|
|
||
| (void) unlink(sa->u.sockaddr_un.sun_path); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, I think the previous one is good enough. If you think it's possible that the temp file can be existing like created manually, it happens very rarely. My thought is based on we need to do more in the future about this feature to clean up sock files. Your way may be used in the future. But now I prefer not to introduce it.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This improvement was motivated by this comment: Yes, this function does not implement a check to see if the socket is abandoned or not. But for this, as recommended everywhere and for similar use in linux, a lock is required, which I feel we will not get to soon.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In addition to my previous answer, I want to note that ignoring the error handling of
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good morning @mar0x, Since you suggested this feature earlier, please let me know what you think of my proposed implementation. Thank you! |
||
| name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; | ||
|
|
||
| if (nxt_socket_release_by_path(name) != NXT_OK) { | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_socket_release_by_path(%FN) failed", | ||
| name); | ||
| goto fail; | ||
| } | ||
|
|
||
| } else { | ||
| orig_sa = NULL; | ||
| } | ||
|
|
||
| #endif | ||
|
|
||
| if (nxt_socket_bind(task, s, sa) != NXT_OK) { | ||
| goto fail; | ||
| } | ||
| if (nxt_socket_bind(task, s, sa, &err) != NXT_OK) { | ||
|
|
||
| #if (NXT_HAVE_UNIX_DOMAIN) | ||
echolimazulu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if (family == AF_UNIX) { | ||
| name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; | ||
| if (sa->u.sockaddr.sa_family == AF_UNIX) { | ||
| switch (err) { | ||
|
|
||
| access = (S_IRUSR | S_IWUSR); | ||
| case EACCES: | ||
| ls->error = NXT_SOCKET_ERROR_ACCESS; | ||
| break; | ||
|
|
||
| if (nxt_file_set_access(name, access) != NXT_OK) { | ||
| goto listen_fail; | ||
| } | ||
| } | ||
| case ENOENT: | ||
| case ENOTDIR: | ||
| ls->error = NXT_SOCKET_ERROR_PATH; | ||
| break; | ||
| } | ||
|
|
||
| } else | ||
| #endif | ||
| { | ||
| switch (err) { | ||
|
|
||
| nxt_debug(task, "listen(%d, %d)", s, ls->backlog); | ||
| case EACCES: | ||
| ls->error = NXT_SOCKET_ERROR_PORT; | ||
| break; | ||
|
|
||
| if (listen(s, ls->backlog) != 0) { | ||
| nxt_alert(task, "listen(%d, %d) failed %E", | ||
| s, ls->backlog, nxt_socket_errno); | ||
| goto listen_fail; | ||
| } | ||
|
|
||
| #if (NXT_HAVE_UNIX_DOMAIN) | ||
| case EADDRINUSE: | ||
| ls->error = NXT_SOCKET_ERROR_INUSE; | ||
| break; | ||
|
|
||
| if (orig_sa != NULL) { | ||
| ts = nxt_socket_create(task, AF_UNIX, SOCK_STREAM, 0, 0); | ||
| if (ts == -1) { | ||
| goto listen_fail; | ||
| case EADDRNOTAVAIL: | ||
| ls->error = NXT_SOCKET_ERROR_NOADDR; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| ret = connect(ts, &orig_sa->u.sockaddr, orig_sa->socklen); | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_socket_bind(%d, %*s) failed %E", | ||
| s, (size_t) sa->length, nxt_sockaddr_start(sa), | ||
| err); | ||
| goto fail; | ||
| } | ||
|
|
||
| err = nxt_socket_errno; | ||
| #if (NXT_HAVE_UNIX_DOMAIN) | ||
|
|
||
| nxt_socket_close(task, ts); | ||
| if (family == AF_UNIX) { | ||
| name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; | ||
|
|
||
| if (ret == 0) { | ||
| nxt_alert(task, "connect(%d, %*s) succeed, address already in use", | ||
| ts, (size_t) orig_sa->length, | ||
| nxt_sockaddr_start(orig_sa)); | ||
| access = (ls->access) ? ls->access : (S_IRUSR | S_IWUSR); | ||
|
|
||
| if (nxt_file_set_access(name, access) != NXT_OK) { | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_file_set_access(%FN) failed", | ||
| name); | ||
| goto listen_fail; | ||
| } | ||
| } | ||
|
|
||
| if (err != NXT_ENOENT && err != NXT_ECONNREFUSED) { | ||
| nxt_alert(task, "connect(%d, %*s) failed %E", | ||
| ts, (size_t) orig_sa->length, | ||
| nxt_sockaddr_start(orig_sa), err); | ||
| #endif | ||
|
|
||
| if (ls->start == NULL) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hongzhidao How do you like this decision? It is fully consistent with the current logic of the listen and router call program.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the current patch is based on the logic from the controller process, as you used
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The moment I noted, does not perform I reproduce new options based on your suggestions and comments as they come in so that we can immediately see the result and move on to the best solution.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I sincerely appreciate your corrections, thank you for this! You can also move this
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry that personally, I can't agree this new way.
We think the ideal solution is to clean up all the unused unix domain socket files.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for your correction. I'll fix But The whole difficulty is that you want to ensure similar work of Please tell me more about your ideal solution. I want to note that cleaning up unused (abandoned) sockets and the problem of reusing sockets at the moment are completely different problems.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If we can clean up unused sockets, then we don't need the way borrowed from
Right, I agree that the way works, but it makes the router more complicated. The router code is already complicated, I prefer not to make it bigger...
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not take it for excessive perseverance and obsession. I'm trying to solve a real problem I'm facing in my projects. The problem is that abandoned and deleted Removing existing sockets must somehow be done during the socket creation process, as it may have been abandoned at the time of the previous unexpected or or early termination of the program. Previously (#670 (comment)) I suggested not using When using cloud platforms, the snap-in sends a SIGKILL signal to the container and it is expected that it will complete all the necessary procedures to close all existing processes: connections, sockets, etc. If the end application does not have time to do this, then the container will be forcefully terminated within 10 seconds after SIGKILL. I understand that in the case of a Unit, 10 seconds is more than enough to terminate all processes, however, but unexpected terminations may not be due to a SIGKILL being passed from a snap.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Seems to be fixed now: 1497d19 |
||
| nxt_debug(task, "listen(%d, %d)", s, ls->backlog); | ||
|
|
||
| if (listen(s, ls->backlog) != 0) { | ||
| err = nxt_socket_errno; | ||
| nxt_alert(task, "listen(%d, %d) failed %E", | ||
| s, ls->backlog, err); | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "listen(%d, %d) failed %E", | ||
| s, ls->backlog, err); | ||
| goto listen_fail; | ||
| } | ||
|
|
||
| tmp = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; | ||
| name = (nxt_file_name_t *) orig_sa->u.sockaddr_un.sun_path; | ||
| #if (NXT_HAVE_UNIX_DOMAIN) | ||
|
|
||
| if (orig_sa != NULL) { | ||
|
|
||
| if (nxt_listen_socket_saddr_check(task, orig_sa) != NXT_OK) { | ||
| nxt_alert(task, "nxt_listen_socket_saddr_check(%*s) failed", | ||
| (size_t) sa->length, nxt_sockaddr_start(sa)); | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_listen_socket_connect(%*s) failed", | ||
| (size_t) sa->length, nxt_sockaddr_start(sa)); | ||
| goto listen_fail; | ||
| } | ||
|
|
||
| tmp = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; | ||
| name = (nxt_file_name_t *) orig_sa->u.sockaddr_un.sun_path; | ||
|
|
||
| if (nxt_file_rename(tmp, name) != NXT_OK) { | ||
| nxt_alert(task, "nxt_file_rename(%FN, %FN) failed", | ||
| tmp, name); | ||
| if (ls->start != NULL && ls->end != NULL) | ||
| ls->end = nxt_sprintf(ls->start, ls->end, | ||
| "nxt_file_rename(%FN, %FN) failed", | ||
| tmp, name); | ||
| goto listen_fail; | ||
| } | ||
|
|
||
| if (nxt_file_rename(tmp, name) != NXT_OK) { | ||
| goto listen_fail; | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
|
|
||
| } | ||
|
|
||
| ls->socket = s; | ||
| thr->log = old; | ||
|
|
||
|
|
@@ -215,6 +290,67 @@ nxt_listen_socket_create(nxt_task_t *task, nxt_mp_t *mp, | |
| } | ||
|
|
||
|
|
||
| nxt_int_t | ||
| nxt_listen_socket_saddr_check(nxt_task_t *task, nxt_sockaddr_t *sa) | ||
| { | ||
| nxt_socket_t ts; | ||
| nxt_int_t ret; | ||
| nxt_err_t err; | ||
|
|
||
| ts = nxt_socket_create(task, AF_UNIX, SOCK_STREAM, 0, 0, NULL); | ||
| if (ts == -1) { | ||
| return NXT_ERROR; | ||
| } | ||
|
|
||
| ret = connect(ts, &sa->u.sockaddr, sa->socklen); | ||
| err = nxt_socket_errno; | ||
|
|
||
| nxt_socket_close(task, ts); | ||
|
|
||
| if (ret == 0) { | ||
| nxt_alert(task, "connect(%d, %*s) succeed, address already in use", | ||
| ts, (size_t) sa->length, | ||
| nxt_sockaddr_start(sa)); | ||
| return NXT_ERROR; | ||
| } | ||
|
|
||
| if (err != NXT_ENOENT && err != NXT_ECONNREFUSED) { | ||
| nxt_alert(task, "connect(%d, %*s) failed %E", | ||
| ts, (size_t) sa->length, | ||
| nxt_sockaddr_start(sa), err); | ||
| return NXT_ERROR; | ||
| } | ||
|
|
||
| return NXT_OK; | ||
| } | ||
|
|
||
|
|
||
| nxt_int_t | ||
| nxt_listen_socket_tmp_rename(nxt_task_t *task, nxt_sockaddr_t *sa) | ||
| { | ||
| size_t TMP_EXT_SIZE = sizeof(NXT_TMP_EXT), | ||
| TMP_SIZE = sa->socklen + TMP_EXT_SIZE, | ||
| name_size; | ||
| nxt_file_name_t tmp[TMP_SIZE], *name; | ||
|
|
||
| nxt_memzero(&tmp, TMP_SIZE); | ||
|
|
||
| name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path; | ||
| name_size = nxt_strlen(name); | ||
|
|
||
| nxt_memcpy(tmp, name, name_size); | ||
| nxt_memcpy(tmp + name_size, NXT_TMP_EXT, TMP_EXT_SIZE); | ||
|
|
||
| if (nxt_file_rename(tmp, name) != NXT_OK) { | ||
| nxt_alert(task, "nxt_file_rename(%FN, %FN) failed", | ||
| tmp, name); | ||
| return NXT_ERROR; | ||
| } | ||
|
|
||
| return NXT_OK; | ||
| } | ||
|
|
||
|
|
||
| nxt_int_t | ||
| nxt_listen_socket_update(nxt_task_t *task, nxt_listen_socket_t *ls, | ||
| nxt_listen_socket_t *prev) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.