2 #include "Connection.hpp"
3 #include "ForkAndExec.hpp"
8 Server::Server(string binary_
, Server::argv_t args_
)
9 : binary
{move(binary_
)}
19 if (holds_alternative
<string
>(socket_or_port
)) {
20 unlink(get
<string
>(socket_or_port
).c_str());
24 static inline string
extractArg(const Server::arg_t
&arg_cont
, const string
&func_arg
) {
25 if (holds_alternative
<string
>(arg_cont
)) {
26 return get
<string
>(arg_cont
);
28 return get
<Server::arg_func_t
>(arg_cont
)(func_arg
);
32 static inline void pushArg(vector
<char *> &arr
, const string
&arg
) {
33 auto len
= arg
.size();
34 auto str
= arg
.data(), end
= str
+ len
+ 1;
35 auto ptr
= new char[len
+ 1];
40 optional
<string
> Server::handleArg(vector
<char *> &arr
, const string
&arg
, const arg_func_t
&next_arg
) {
42 if (arg
== "-p" || arg
== "--port") {
43 auto port
= next_arg(arg
);
45 // pushArg(arr, "-U");
46 // pushArg(arr, port);
47 socket_or_port
= stoi(port
);
49 } else if (arg
== "-s" || arg
== "--unix-socket") {
50 auto sock
= next_arg(arg
);
52 socket_or_port
= sock
;
54 } else if (arg
== "-S" || arg
== "--enable-sasl") {
61 vector
<char *> Server::createArgv() {
67 for (auto it
= args
.cbegin(); it
!= args
.cend(); ++it
) {
68 if (holds_alternative
<arg_t
>(*it
)) {
70 auto arg
= extractArg(get
<arg_t
>(*it
), binary
);
71 handleArg(arr
, arg
, [&it
](const string
&arg_
) {
72 return extractArg(get
<arg_t
>(*++it
), arg_
);
76 auto &[one
, two
] = get
<arg_pair_t
>(*it
);
77 auto arg_one
= extractArg(one
, binary
);
78 auto arg_two
= extractArg(two
, arg_one
);
80 auto next
= handleArg(arr
, arg_one
, [&arg_two
](const string
&) {
84 if (!next
.has_value()) {
85 pushArg(arr
, arg_two
);
90 arr
.push_back(nullptr);
95 optional
<Server::ChildProc
> Server::start() {
97 auto argv
= createArgv();
98 ForkAndExec fork_and_exec
{binary
.c_str(), argv
.data()};
100 pipe
= fork_and_exec
.createPipe();
101 pid
= fork_and_exec();
103 for (auto argp
: argv
) {
111 return ChildProc
{pid
, pipe
};
114 bool Server::isListening() {
117 if (holds_alternative
<string
>(socket_or_port
)) {
118 if (memcached_server_add_unix_socket(*memc
, get
<string
>(socket_or_port
).c_str())) {
122 if (memcached_server_add(*memc
, "localhost", get
<int>(socket_or_port
))) {
128 memcached_behavior_set(*memc
, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL
, 1);
129 memcached_set_sasl_auth_data(*memc
, "memcached", "memcached");
132 Malloced
stat(memcached_stat(*memc
, nullptr, nullptr));
133 if (!*stat
|| !stat
->pid
|| stat
->pid
!= pid
) {
140 bool Server::stop() {
144 if (signalled
[SIGTERM
]) {
145 return signal(SIGKILL
);
147 return signal(SIGTERM
);
151 bool Server::signal(int signo
) {
155 signalled
[signo
] += 1;
156 return 0 <= kill(pid
, signo
);
159 bool Server::check() {
163 bool Server::wait(int flags
) {
164 if (pid
&& pid
== waitpid(pid
, &status
, flags
)) {
165 if (drain().length()) {
166 cerr
<< "Ouput of " << *this << ":\n" << output
<< endl
;
179 bool Server::tryWait() {
180 return wait(WNOHANG
);
183 Server::Server(const Server
&s
) {
186 socket_or_port
= s
.socket_or_port
;
189 Server
&Server::operator=(const Server
&s
) {
192 socket_or_port
= s
.socket_or_port
;
196 pid_t
Server::getPid() const {
200 const string
&Server::getBinary() const {
204 const Server::argv_t
&Server::getArgs() const {
208 const socket_or_port_t
&Server::getSocketOrPort() const {
209 return socket_or_port
;
212 int Server::getPipe() const {
216 string
&Server::drain() {
219 char read_buf
[1<<12];
220 auto read_len
= read(pipe
, read_buf
, sizeof(read_buf
));
223 output
.append(read_buf
, read_len
);
226 if (read_len
== -1) {
231 perror("Server::drain read()");
234 #if EWOULDBLOCK != EAGAIN