Index: net/tools/flip_server/flip_in_mem_edsm_server.cc |
=================================================================== |
--- net/tools/flip_server/flip_in_mem_edsm_server.cc (revision 71892) |
+++ net/tools/flip_server/flip_in_mem_edsm_server.cc (working copy) |
@@ -6,6 +6,8 @@ |
#include <netinet/tcp.h> // For TCP_NODELAY |
#include <sys/socket.h> |
#include <sys/types.h> |
+#include <sys/file.h> |
+#include <sys/stat.h> |
#include <unistd.h> |
#include <openssl/err.h> |
#include <openssl/ssl.h> |
@@ -48,6 +50,7 @@ |
using std::string; |
using std::vector; |
using std::cout; |
+using std::cerr; |
//////////////////////////////////////////////////////////////////////////////// |
@@ -61,6 +64,8 @@ |
#define SSL_CTX_DEFAULT_CIPHER_LIST "!aNULL:!ADH:!eNull:!LOW:!EXP:RC4+RSA:MEDIUM:HIGH" |
+#define PIDFILE "/var/run/flip-server.pid" |
+ |
// If true, then disables the nagle algorithm); |
bool FLAGS_disable_nagle = true; |
@@ -289,13 +294,26 @@ |
bool delete_when_done; |
size_t index; |
DataFrame() : data(NULL), size(0), delete_when_done(false), index(0) {} |
- void MaybeDelete() { |
+ virtual void MaybeDelete() { |
if (delete_when_done) { |
delete[] data; |
} |
} |
+ virtual ~DataFrame() { |
+ MaybeDelete(); |
+ } |
}; |
+class SpdyFrameDataFrame : public DataFrame { |
+ public: |
+ SpdyFrame* frame; |
+ virtual void MaybeDelete() { |
+ if (delete_when_done) { |
+ delete frame; |
+ } |
+ } |
+}; |
+ |
//////////////////////////////////////////////////////////////////////////////// |
class StoreBodyAndHeadersVisitor: public BalsaVisitorInterface { |
@@ -698,6 +716,7 @@ |
int fd, |
string server_ip, |
string server_port, |
+ string remote_ip, |
bool use_ssl) = 0; |
virtual size_t ProcessReadInput(const char* data, size_t len) = 0; |
virtual size_t ProcessWriteInput(const char* data, size_t len) = 0; |
@@ -741,7 +760,7 @@ |
class HttpSM; |
class SMConnection; |
-typedef list<DataFrame> OutputList; |
+typedef list<DataFrame*> OutputList; |
class SMConnectionPoolInterface { |
public: |
@@ -796,7 +815,8 @@ |
sm_interface_(NULL), |
log_prefix_(log_prefix), |
max_bytes_sent_per_dowrite_(4096), |
- ssl_(NULL) |
+ ssl_(NULL), |
+ last_read_time_(0) |
{} |
int fd_; |
@@ -828,6 +848,7 @@ |
SSL* ssl_; |
public: |
+ time_t last_read_time_; |
string server_ip_; |
string server_port_; |
@@ -839,10 +860,10 @@ |
<< "Setting ready to send: EPOLLIN | EPOLLOUT"; |
epoll_server_->SetFDReady(fd_, EPOLLIN | EPOLLOUT); |
} |
- void EnqueueDataFrame(const DataFrame& df) { |
+ void EnqueueDataFrame(DataFrame* df) { |
output_list_.push_back(df); |
VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "EnqueueDataFrame: " |
- << "size = " << df.size << ": Setting FD ready."; |
+ << "size = " << df->size << ": Setting FD ready."; |
ReadyToSend(); |
} |
int fd() { return fd_; } |
@@ -871,12 +892,15 @@ |
int fd, |
string server_ip, |
string server_port, |
+ string remote_ip, |
bool use_ssl) { |
if (initialized_) { |
LOG(FATAL) << "Attempted to initialize already initialized server"; |
return; |
} |
+ client_ip_ = remote_ip; |
+ |
if (fd == -1) { |
// If fd == -1, then we are initializing a new connection that will |
// connect to the backend. |
@@ -921,23 +945,12 @@ |
} |
fd_ = fd; |
- struct sockaddr sock_addr; |
- socklen_t addr_size = sizeof(sock_addr); |
- addr_size = sizeof(sock_addr); |
- int res = getsockname(fd_, &sock_addr, &addr_size); |
- if (res < 0) { |
- LOG(ERROR) << "Could not get socket address for fd " << fd_ |
- << ": getsockname: " << strerror(errno); |
- } else { |
- struct sockaddr_in *sock_addr_in = (struct sockaddr_in *)&sock_addr; |
- char ip[16]; |
- snprintf(ip, sizeof(ip), "%d.%d.%d.%d", |
- IPV4_PRINTABLE_FORMAT(sock_addr_in->sin_addr.s_addr)); |
- client_ip_ = ip; |
- } |
} |
registered_in_epoll_server_ = false; |
+ // Set the last read time here as the idle checker will start from |
+ // now. |
+ last_read_time_ = time(NULL); |
initialized_ = true; |
connection_pool_ = connection_pool; |
@@ -991,6 +1004,12 @@ |
if (rv != chunksize) |
break; // If we couldn't write everything, we're implicitly stalled |
} |
+ if (!(flags & MSG_MORE)) { |
+ int state = 0; |
+ setsockopt( fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof( state ) ); |
+ state = 1; |
+ setsockopt( fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof( state ) ); |
+ } |
} else { |
bytes_written = send(fd_, data, len, flags); |
} |
@@ -1019,7 +1038,7 @@ |
} |
void Cleanup(const char* cleanup) { |
- VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Cleanup"; |
+ VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Cleanup: " << cleanup; |
if (!initialized_) { |
return; |
} |
@@ -1030,6 +1049,7 @@ |
if (sm_interface_) { |
sm_interface_->ResetForNewConnection(); |
} |
+ last_read_time_ = 0; |
} |
private: |
@@ -1132,6 +1152,7 @@ |
} else if (bytes_read > 0) { |
VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "read " << bytes_read |
<< " bytes"; |
+ last_read_time_ = time(NULL); |
if (!protocol_detected_) { |
if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) { |
// Http Server |
@@ -1303,11 +1324,11 @@ |
if (sm_interface_ && output_list_.size() < 2) { |
sm_interface_->GetOutput(); |
} |
- DataFrame& data_frame = output_list_.front(); |
- const char* bytes = data_frame.data; |
- int size = data_frame.size; |
- bytes += data_frame.index; |
- size -= data_frame.index; |
+ DataFrame* data_frame = output_list_.front(); |
+ const char* bytes = data_frame->data; |
+ int size = data_frame->size; |
+ bytes += data_frame->index; |
+ size -= data_frame->index; |
DCHECK_GE(size, 0); |
if (size <= 0) { |
// Empty data frame. Indicates end of data from client. |
@@ -1315,8 +1336,8 @@ |
int state = 0; |
VLOG(2) << log_prefix_ << "Empty data frame, uncorking socket."; |
setsockopt( fd_, IPPROTO_TCP, TCP_CORK, &state, sizeof( state ) ); |
- data_frame.MaybeDelete(); |
output_list_.pop_front(); |
+ delete data_frame; |
continue; |
} |
@@ -1349,7 +1370,7 @@ |
} else if (bytes_written > 0) { |
VLOG(2) << log_prefix_ << ACCEPTOR_CLIENT_IDENT << "Wrote: " |
<< bytes_written << " bytes"; |
- data_frame.index += bytes_written; |
+ data_frame->index += bytes_written; |
bytes_sent += bytes_written; |
continue; |
} else if (bytes_written == -2) { |
@@ -1384,6 +1405,7 @@ |
PrintSslError(); |
SSL_free(ssl_); |
PrintSslError(); |
+ ssl_ = NULL; |
} |
if (registered_in_epoll_server_) { |
epoll_server_->UnregisterFD(fd_); |
@@ -1398,6 +1420,12 @@ |
initialized_ = false; |
protocol_detected_ = false; |
events_ = 0; |
+ for (list<DataFrame*>::iterator i = |
+ output_list_.begin(); |
+ i != output_list_.end(); |
+ ++i) { |
+ delete *i; |
+ } |
output_list_.clear(); |
} |
@@ -1639,12 +1667,13 @@ |
int fd, |
string server_ip, |
string server_port, |
+ string remote_ip, |
bool use_ssl) { |
VLOG(2) << ACCEPTOR_CLIENT_IDENT |
<< "SpdySM: Initializing server connection."; |
connection_->InitSMConnection(connection_pool, sm_interface, |
epoll_server, fd, server_ip, server_port, |
- use_ssl); |
+ remote_ip, use_ssl); |
} |
private: |
@@ -1690,13 +1719,13 @@ |
sm_http_interface->InitSMInterface(this, server_idx); |
sm_http_interface->InitSMConnection(NULL, sm_http_interface, |
epoll_server_, -1, |
- server_ip, server_port, false); |
+ server_ip, server_port, "", false); |
return sm_http_interface; |
} |
int SpdyHandleNewStream(const SpdyControlFrame* frame, |
- string *http_data, |
+ string &http_data, |
bool *is_https_scheme) |
{ |
bool parsed_headers = false; |
@@ -1743,21 +1772,21 @@ |
filename); |
} else { |
SpdyHeaderBlock::iterator version = headers.find("version"); |
- *http_data += method->second + " " + uri + " " + version->second + "\r\n"; |
+ http_data += method->second + " " + uri + " " + version->second + "\r\n"; |
VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Request: " << method->second << " " |
<< uri << " " << version->second; |
for (SpdyHeaderBlock::iterator i = headers.begin(); |
i != headers.end(); ++i) { |
- *http_data += i->first + ": " + i->second + "\r\n"; |
+ http_data += i->first + ": " + i->second + "\r\n"; |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << i->first.c_str() << ":" |
<< i->second.c_str(); |
} |
if (g_proxy_config.forward_ip_header_enabled_) { |
// X-Client-Cluster-IP header |
- *http_data += g_proxy_config.forward_ip_header_ + ": " + |
+ http_data += g_proxy_config.forward_ip_header_ + ": " + |
connection_->client_ip() + "\r\n"; |
} |
- *http_data += "\r\n"; |
+ http_data += "\r\n"; |
} |
VLOG(3) << ACCEPTOR_CLIENT_IDENT << "SpdySM: HTTP Request:\n" << http_data; |
@@ -1775,7 +1804,7 @@ |
string http_data; |
bool is_https_scheme; |
- int ret = SpdyHandleNewStream(frame, &http_data, &is_https_scheme); |
+ int ret = SpdyHandleNewStream(frame, http_data, &is_https_scheme); |
if (!ret) { |
LOG(ERROR) << "SpdySM: Could not convert spdy into http."; |
break; |
@@ -1879,8 +1908,7 @@ |
// some logic review and method renaming is probably in order. |
void Cleanup() {} |
- // Send a settings frame and possibly some NOOP packets to force |
- // opening of cwnd |
+ // Send a settings frame |
int PostAcceptHook() { |
ssize_t bytes_written; |
spdy::SpdySettings settings; |
@@ -2042,11 +2070,12 @@ |
SpdySynStreamControlFrame* fsrcf = |
spdy_framer_->CreateSynStream(stream_id, 0, 0, CONTROL_FLAG_NONE, true, |
&block); |
- DataFrame df; |
- df.size = fsrcf->length() + SpdyFrame::size(); |
- size_t df_size = df.size; |
- df.data = fsrcf->data(); |
- df.delete_when_done = true; |
+ SpdyFrameDataFrame* df = new SpdyFrameDataFrame; |
+ df->size = fsrcf->length() + SpdyFrame::size(); |
+ size_t df_size = df->size; |
+ df->data = fsrcf->data(); |
+ df->frame = fsrcf; |
+ df->delete_when_done = true; |
EnqueueDataFrame(df); |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynStreamheader " |
@@ -2063,11 +2092,12 @@ |
SpdySynReplyControlFrame* fsrcf = |
spdy_framer_->CreateSynReply(stream_id, CONTROL_FLAG_NONE, true, &block); |
- DataFrame df; |
- df.size = fsrcf->length() + SpdyFrame::size(); |
- size_t df_size = df.size; |
- df.data = fsrcf->data(); |
- df.delete_when_done = true; |
+ SpdyFrameDataFrame* df = new SpdyFrameDataFrame; |
+ df->size = fsrcf->length() + SpdyFrame::size(); |
+ size_t df_size = df->size; |
+ df->data = fsrcf->data(); |
+ df->frame = fsrcf; |
+ df->delete_when_done = true; |
EnqueueDataFrame(df); |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending SynReplyheader " |
@@ -2084,14 +2114,13 @@ |
// TODO(mbelshe): We can't compress here - before going into the |
// priority queue. Compression needs to be done |
// with late binding. |
- |
if (len == 0) { |
SpdyDataFrame* fdf = spdy_framer_->CreateDataFrame(stream_id, data, len, |
flags); |
- DataFrame df; |
- df.size = fdf->length() + SpdyFrame::size(); |
- df.data = fdf->data(); |
- df.delete_when_done = true; |
+ SpdyFrameDataFrame* df = new SpdyFrameDataFrame; |
+ df->size = fdf->length() + SpdyFrame::size(); |
+ df->data = fdf->data(); |
+ df->delete_when_done = true; |
EnqueueDataFrame(df); |
return; |
} |
@@ -2109,10 +2138,10 @@ |
SpdyDataFrame* fdf = spdy_framer_->CreateDataFrame(stream_id, data, size, |
chunk_flags); |
- DataFrame df; |
- df.size = fdf->length() + SpdyFrame::size(); |
- df.data = fdf->data(); |
- df.delete_when_done = true; |
+ SpdyFrameDataFrame* df = new SpdyFrameDataFrame; |
+ df->size = fdf->length() + SpdyFrame::size(); |
+ df->data = fdf->data(); |
+ df->delete_when_done = true; |
EnqueueDataFrame(df); |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Sending data frame " |
@@ -2124,7 +2153,7 @@ |
} |
} |
- void EnqueueDataFrame(const DataFrame& df) { |
+ void EnqueueDataFrame(DataFrame* df) { |
connection_->EnqueueDataFrame(df); |
} |
@@ -2323,13 +2352,14 @@ |
int fd, |
string server_ip, |
string server_port, |
+ string remote_ip, |
bool use_ssl) |
{ |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Initializing server " |
<< "connection."; |
connection_->InitSMConnection(connection_pool, sm_interface, |
epoll_server, fd, server_ip, server_port, |
- use_ssl); |
+ remote_ip, use_ssl); |
} |
size_t ProcessReadInput(const char* data, size_t len) { |
@@ -2343,10 +2373,10 @@ |
<< len << ": stream " << stream_id_; |
char * dataPtr = new char[len]; |
memcpy(dataPtr, data, len); |
- DataFrame data_frame; |
- data_frame.data = (const char *)dataPtr; |
- data_frame.size = len; |
- data_frame.delete_when_done = true; |
+ DataFrame* data_frame = new DataFrame; |
+ data_frame->data = (const char *)dataPtr; |
+ data_frame->size = len; |
+ data_frame->delete_when_done = true; |
connection_->EnqueueDataFrame(data_frame); |
return len; |
} |
@@ -2450,10 +2480,10 @@ |
private: |
void SendEOFImpl(uint32 stream_id) { |
- DataFrame df; |
- df.data = "0\r\n\r\n"; |
- df.size = 5; |
- df.delete_when_done = false; |
+ DataFrame* df = new DataFrame; |
+ df->data = "0\r\n\r\n"; |
+ df->size = 5; |
+ df->delete_when_done = false; |
EnqueueDataFrame(df); |
if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) { |
Reset(); |
@@ -2485,15 +2515,15 @@ |
size_t SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) { |
SimpleBuffer sb; |
headers.WriteHeaderAndEndingToBuffer(&sb); |
- DataFrame df; |
- df.size = sb.ReadableBytes(); |
- char* buffer = new char[df.size]; |
- df.data = buffer; |
- df.delete_when_done = true; |
- sb.Read(buffer, df.size); |
+ DataFrame* df = new DataFrame; |
+ df->size = sb.ReadableBytes(); |
+ char* buffer = new char[df->size]; |
+ df->data = buffer; |
+ df->delete_when_done = true; |
+ sb.Read(buffer, df->size); |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header " |
<< stream_id_; |
- size_t df_size = df.size; |
+ size_t df_size = df->size; |
EnqueueDataFrame(df); |
return df_size; |
} |
@@ -2501,15 +2531,15 @@ |
size_t SendSynStreamImpl(uint32 stream_id, const BalsaHeaders& headers) { |
SimpleBuffer sb; |
headers.WriteHeaderAndEndingToBuffer(&sb); |
- DataFrame df; |
- df.size = sb.ReadableBytes(); |
- char* buffer = new char[df.size]; |
- df.data = buffer; |
- df.delete_when_done = true; |
- sb.Read(buffer, df.size); |
+ DataFrame* df = new DataFrame; |
+ df->size = sb.ReadableBytes(); |
+ char* buffer = new char[df->size]; |
+ df->data = buffer; |
+ df->delete_when_done = true; |
+ sb.Read(buffer, df->size); |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header " |
<< stream_id_; |
- size_t df_size = df.size; |
+ size_t df_size = df->size; |
EnqueueDataFrame(df); |
return df_size; |
} |
@@ -2519,18 +2549,18 @@ |
char chunk_buf[128]; |
snprintf(chunk_buf, sizeof(chunk_buf), "%x\r\n", (unsigned int)len); |
string chunk_description(chunk_buf); |
- DataFrame df; |
- df.size = chunk_description.size() + len + 2; |
- char* buffer = new char[df.size]; |
- df.data = buffer; |
- df.delete_when_done = true; |
+ DataFrame* df = new DataFrame; |
+ df->size = chunk_description.size() + len + 2; |
+ char* buffer = new char[df->size]; |
+ df->data = buffer; |
+ df->delete_when_done = true; |
memcpy(buffer, chunk_description.data(), chunk_description.size()); |
memcpy(buffer + chunk_description.size(), data, len); |
memcpy(buffer + chunk_description.size() + len, "\r\n", 2); |
EnqueueDataFrame(df); |
} |
- void EnqueueDataFrame(const DataFrame& df) { |
+ void EnqueueDataFrame(DataFrame* df) { |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream " |
<< stream_id_; |
connection_->EnqueueDataFrame(df); |
@@ -2610,13 +2640,14 @@ |
int fd, |
string server_ip, |
string server_port, |
+ string remote_ip, |
bool use_ssl) |
{ |
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "StreamerSM: Initializing server " |
<< "connection."; |
connection_->InitSMConnection(connection_pool, sm_interface, |
epoll_server, fd, server_ip, |
- server_port, use_ssl); |
+ server_port, remote_ip, use_ssl); |
} |
size_t ProcessReadInput(const char* data, size_t len) { |
@@ -2626,10 +2657,10 @@ |
size_t ProcessWriteInput(const char* data, size_t len) { |
char * dataPtr = new char[len]; |
memcpy(dataPtr, data, len); |
- DataFrame df; |
- df.data = (const char *)dataPtr; |
- df.size = len; |
- df.delete_when_done = true; |
+ DataFrame* df = new DataFrame; |
+ df->data = (const char *)dataPtr; |
+ df->size = len; |
+ df->delete_when_done = true; |
connection_->EnqueueDataFrame(df); |
return len; |
} |
@@ -2684,6 +2715,7 @@ |
epoll_server_, -1, |
acceptor_->https_server_ip_, |
acceptor_->https_server_port_, |
+ "", |
false); |
return 1; |
@@ -2773,6 +2805,7 @@ |
vector<SMConnection*> unused_server_connections_; |
vector<SMConnection*> tmp_unused_server_connections_; |
vector<SMConnection*> allocated_server_connections_; |
+ list<SMConnection*> active_server_connections_; |
Notification quitting_; |
MemoryCache* memory_cache_; |
public: |
@@ -2806,6 +2839,7 @@ |
++i) { |
delete *i; |
} |
+ delete ssl_state_; |
} |
SMConnection* NewConnection() { |
@@ -2832,7 +2866,7 @@ |
epoll_server_.RegisterFD(acceptor_->listen_fd_, this, EPOLLIN | EPOLLET); |
} |
- void HandleConnection(int server_fd) { |
+ void HandleConnection(int server_fd, struct sockaddr_in *remote_addr) { |
int on = 1; |
int rc; |
if (acceptor_->disable_nagle_) { |
@@ -2851,12 +2885,15 @@ |
close(server_fd); |
return; |
} |
+ string remote_ip = inet_ntoa(remote_addr->sin_addr); |
server_connection->InitSMConnection(this, |
NULL, |
&epoll_server_, |
server_fd, |
- "", "", |
+ "", "", remote_ip, |
use_ssl_); |
+ if (server_connection->initialized()) |
+ active_server_connections_.push_back(server_connection); |
} |
void AcceptFromListenFD() { |
@@ -2874,7 +2911,7 @@ |
break; |
} |
VLOG(1) << ACCEPTOR_CLIENT_IDENT << " Accepted connection"; |
- HandleConnection(fd); |
+ HandleConnection(fd, (struct sockaddr_in *)&address); |
} |
} else { |
while (true) { |
@@ -2890,7 +2927,7 @@ |
break; |
} |
VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Accepted connection"; |
- HandleConnection(fd); |
+ HandleConnection(fd, (struct sockaddr_in *)&address); |
} |
} |
} |
@@ -2912,6 +2949,32 @@ |
quitting_.Notify(); |
} |
+ // Iterates through a list of active connections expiring any that have been |
+ // idle longer than the configured timeout. |
+ void HandleConnectionIdleTimeout() { |
+ int cur_time = time(NULL); |
+ static time_t oldest_time = cur_time; |
+ // Only iterate the list if we speculate that a connection is ready to be |
+ // expired |
+ if ((cur_time - oldest_time) < g_proxy_config.idle_timeout_s_) |
+ return; |
+ list<SMConnection*>::iterator iter = active_server_connections_.begin(); |
+ while (iter != active_server_connections_.end()) { |
+ SMConnection *conn = *iter; |
+ int elapsed_time = (cur_time - conn->last_read_time_); |
+ if (elapsed_time > g_proxy_config.idle_timeout_s_) { |
+ conn->Cleanup("Connection idle timeout reached."); |
+ iter = active_server_connections_.erase(iter); |
+ continue; |
+ } |
+ if (conn->last_read_time_ < oldest_time) |
+ oldest_time = conn->last_read_time_; |
+ iter++; |
+ } |
+ if ((cur_time - oldest_time) >= g_proxy_config.idle_timeout_s_) |
+ oldest_time = cur_time; |
+ } |
+ |
void Run() { |
while (!quitting_.HasBeenNotified()) { |
epoll_server_.set_timeout_in_us(10 * 1000); // 10 ms |
@@ -2920,6 +2983,7 @@ |
tmp_unused_server_connections_.begin(), |
tmp_unused_server_connections_.end()); |
tmp_unused_server_connections_.clear(); |
+ HandleConnectionIdleTimeout(); |
} |
} |
@@ -3000,12 +3064,76 @@ |
//////////////////////////////////////////////////////////////////////////////// |
+static bool wantExit = false; |
+static bool wantLogClose = false; |
+void SignalHandler(int signum) |
+{ |
+ switch(signum) { |
+ case SIGTERM: |
+ case SIGINT: |
+ wantExit = true; |
+ break; |
+ case SIGHUP: |
+ wantLogClose = true; |
+ break; |
+ } |
+} |
+ |
+static int OpenPidFile(const char *pidfile) |
+{ |
+ int fd; |
+ struct stat pid_stat; |
+ int ret; |
+ |
+ fd = open(pidfile, O_RDWR | O_CREAT, 0600); |
+ if (fd == -1) { |
+ cerr << "Could not open pid file '" << pidfile << "' for reading.\n"; |
+ exit(1); |
+ } |
+ |
+ ret = flock(fd, LOCK_EX | LOCK_NB); |
+ if (ret == -1) { |
+ if (errno == EWOULDBLOCK) { |
+ cerr << "Flip server is already running.\n"; |
+ } else { |
+ cerr << "Error getting lock on pid file: " << strerror(errno) << "\n"; |
+ } |
+ exit(1); |
+ } |
+ |
+ if (fstat(fd, &pid_stat) == -1) { |
+ cerr << "Could not stat pid file '" << pidfile << "': " << strerror(errno) |
+ << "\n"; |
+ } |
+ if (pid_stat.st_size != 0) { |
+ if (ftruncate(fd, pid_stat.st_size) == -1) { |
+ cerr << "Could not truncate pid file '" << pidfile << "': " |
+ << strerror(errno) << "\n"; |
+ } |
+ } |
+ |
+ char pid_str[8]; |
+ snprintf(pid_str, sizeof(pid_str), "%d", getpid()); |
+ int bytes = static_cast<int>(strlen(pid_str)); |
+ if (write(fd, pid_str, strlen(pid_str)) != bytes) { |
+ cerr << "Could not write pid file: " << strerror(errno) << "\n"; |
+ close(fd); |
+ exit(1); |
+ } |
+ |
+ return fd; |
+} |
+ |
int main (int argc, char**argv) |
{ |
unsigned int i = 0; |
bool wait_for_iface = false; |
+ int pidfile_fd; |
signal(SIGPIPE, SIG_IGN); |
+ signal(SIGTERM, SignalHandler); |
+ signal(SIGINT, SignalHandler); |
+ signal(SIGHUP, SignalHandler); |
CommandLine::Init(argc, argv); |
CommandLine cl(argc, argv); |
@@ -3027,10 +3155,10 @@ |
<< "\t through the proxy listen ip:port.\n"; |
cout << "\t--forward-ip-header=<header name>\n"; |
cout << "\n Server options:\n"; |
- cout << "\t--spdy-server=\"<listen ip>,<listen port>,[ssl cert filename],\n" |
- << "\t [ssl key filename]\"\n"; |
- cout << "\t--http-server=\"<listen ip>,<listen port>,[ssl cert filename],\n" |
- << "\t [ssl key filename]\"\n"; |
+ cout << "\t--spdy-server=\"<listen ip>,<listen port>,[ssl cert filename]," |
+ << "\n\t [ssl key filename]\"\n"; |
+ cout << "\t--http-server=\"<listen ip>,<listen port>,[ssl cert filename]," |
+ << "\n\t [ssl key filename]\"\n"; |
cout << "\t * Leaving the ssl cert and key fields empty will disable ssl" |
<< " for the\n" |
<< "\t http and spdy flip servers\n"; |
@@ -3042,10 +3170,18 @@ |
<< " raised.\n"; |
cout << "\t--ssl-session-expiry=<seconds> (default is 300)\n"; |
cout << "\t--ssl-disable-compression\n"; |
+ cout << "\t--idle-timeout=<seconds> (default is 300)\n"; |
+ cout << "\t--pidfile=<filepath> (default /var/run/flip-server.pid)\n"; |
cout << "\t--help\n"; |
exit(0); |
} |
+ if (cl.HasSwitch("pidfile")) { |
+ pidfile_fd = OpenPidFile(cl.GetSwitchValueASCII("pidfile").c_str()); |
+ } else { |
+ pidfile_fd = OpenPidFile(PIDFILE); |
+ } |
+ |
g_proxy_config.server_think_time_in_s_ = FLAGS_server_think_time_in_s; |
if (cl.HasSwitch("forward-ip-header")) { |
@@ -3089,13 +3225,18 @@ |
if (cl.HasSwitch("ssl-session-expiry")) { |
string session_expiry = cl.GetSwitchValueASCII("ssl-session-expiry"); |
- g_proxy_config.ssl_session_expiry_ = atoi( session_expiry.c_str() ); |
+ g_proxy_config.ssl_session_expiry_ = atoi(session_expiry.c_str()); |
} |
if (cl.HasSwitch("ssl-disable-compression")) { |
g_proxy_config.ssl_disable_compression_ = true; |
} |
+ if (cl.HasSwitch("idle-timeout")) { |
+ g_proxy_config.idle_timeout_s_ = |
+ atoi(cl.GetSwitchValueASCII("idle-timeout").c_str()); |
+ } |
+ |
if (cl.HasSwitch("force_spdy")) |
FLAGS_force_spdy = true; |
@@ -3116,13 +3257,15 @@ |
LOG(INFO) << "Accepts per wake : " << FLAGS_accepts_per_wake; |
LOG(INFO) << "Disable nagle : " |
<< (FLAGS_disable_nagle?"true":"false"); |
- LOG(INFO) << "Reuseport : " << (FLAGS_reuseport?"true":"false"); |
+ LOG(INFO) << "Reuseport : " |
+ << (FLAGS_reuseport?"true":"false"); |
LOG(INFO) << "Force SPDY : " |
<< (FLAGS_force_spdy?"true":"false"); |
LOG(INFO) << "SSL session expiry : " |
<< g_proxy_config.ssl_session_expiry_; |
LOG(INFO) << "SSL disable compression : " |
<< g_proxy_config.ssl_disable_compression_; |
+ LOG(INFO) << "Connection idle timeout : " << g_proxy_config.idle_timeout_s_; |
// Proxy Acceptors |
while (true) { |
@@ -3209,7 +3352,14 @@ |
sm_worker_threads_.back()->Start(); |
} |
- while (true) { |
+ while (!wantExit) { |
+ // Close logfile when HUP signal is received. Logging system will |
+ // automatically reopen on next log message. |
+ if ( wantLogClose ) { |
+ wantLogClose = false; |
+ VLOG(1) << "HUP received, reopening log file."; |
+ logging::CloseLogFile(); |
+ } |
if (GotQuitFromStdin()) { |
for (unsigned int i = 0; i < sm_worker_threads_.size(); ++i) { |
sm_worker_threads_[i]->Quit(); |
@@ -3217,10 +3367,12 @@ |
for (unsigned int i = 0; i < sm_worker_threads_.size(); ++i) { |
sm_worker_threads_[i]->Join(); |
} |
- return 0; |
+ break; |
} |
usleep(1000*10); // 10 ms |
} |
+ unlink(PIDFILE); |
+ close(pidfile_fd); |
return 0; |
} |