git

Форк
0
/
unix-stream-server.c 
125 строк · 2.9 Кб
1
#include "git-compat-util.h"
2
#include "lockfile.h"
3
#include "unix-socket.h"
4
#include "unix-stream-server.h"
5

6
#define DEFAULT_LOCK_TIMEOUT (100)
7

8
/*
9
 * Try to connect to a unix domain socket at `path` (if it exists) and
10
 * see if there is a server listening.
11
 *
12
 * We don't know if the socket exists, whether a server died and
13
 * failed to cleanup, or whether we have a live server listening, so
14
 * we "poke" it.
15
 *
16
 * We immediately hangup without sending/receiving any data because we
17
 * don't know anything about the protocol spoken and don't want to
18
 * block while writing/reading data.  It is sufficient to just know
19
 * that someone is listening.
20
 */
21
static int is_another_server_alive(const char *path,
22
				   const struct unix_stream_listen_opts *opts)
23
{
24
	int fd = unix_stream_connect(path, opts->disallow_chdir);
25
	if (fd >= 0) {
26
		close(fd);
27
		return 1;
28
	}
29

30
	return 0;
31
}
32

33
int unix_ss_create(const char *path,
34
		   const struct unix_stream_listen_opts *opts,
35
		   long timeout_ms,
36
		   struct unix_ss_socket **new_server_socket)
37
{
38
	struct lock_file lock = LOCK_INIT;
39
	int fd_socket;
40
	struct unix_ss_socket *server_socket;
41

42
	*new_server_socket = NULL;
43

44
	if (timeout_ms < 0)
45
		timeout_ms = DEFAULT_LOCK_TIMEOUT;
46

47
	/*
48
	 * Create a lock at "<path>.lock" if we can.
49
	 */
50
	if (hold_lock_file_for_update_timeout(&lock, path, 0, timeout_ms) < 0)
51
		return -1;
52

53
	/*
54
	 * If another server is listening on "<path>" give up.  We do not
55
	 * want to create a socket and steal future connections from them.
56
	 */
57
	if (is_another_server_alive(path, opts)) {
58
		rollback_lock_file(&lock);
59
		errno = EADDRINUSE;
60
		return -2;
61
	}
62

63
	/*
64
	 * Create and bind to a Unix domain socket at "<path>".
65
	 */
66
	fd_socket = unix_stream_listen(path, opts);
67
	if (fd_socket < 0) {
68
		int saved_errno = errno;
69
		rollback_lock_file(&lock);
70
		errno = saved_errno;
71
		return -1;
72
	}
73

74
	server_socket = xcalloc(1, sizeof(*server_socket));
75
	server_socket->path_socket = strdup(path);
76
	server_socket->fd_socket = fd_socket;
77
	lstat(path, &server_socket->st_socket);
78

79
	*new_server_socket = server_socket;
80

81
	/*
82
	 * Always rollback (just delete) "<path>.lock" because we already created
83
	 * "<path>" as a socket and do not want to commit_lock to do the atomic
84
	 * rename trick.
85
	 */
86
	rollback_lock_file(&lock);
87

88
	return 0;
89
}
90

91
void unix_ss_free(struct unix_ss_socket *server_socket)
92
{
93
	if (!server_socket)
94
		return;
95

96
	if (server_socket->fd_socket >= 0) {
97
		if (!unix_ss_was_stolen(server_socket))
98
			unlink(server_socket->path_socket);
99
		close(server_socket->fd_socket);
100
	}
101

102
	free(server_socket->path_socket);
103
	free(server_socket);
104
}
105

106
int unix_ss_was_stolen(struct unix_ss_socket *server_socket)
107
{
108
	struct stat st_now;
109

110
	if (!server_socket)
111
		return 0;
112

113
	if (lstat(server_socket->path_socket, &st_now) == -1)
114
		return 1;
115

116
	if (st_now.st_ino != server_socket->st_socket.st_ino)
117
		return 1;
118
	if (st_now.st_dev != server_socket->st_socket.st_dev)
119
		return 1;
120

121
	if (!S_ISSOCK(st_now.st_mode))
122
		return 1;
123

124
	return 0;
125
}
126

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.