-
-
Notifications
You must be signed in to change notification settings - Fork 226
/
Copy pathtapplicationserverbase_unix.cpp
132 lines (107 loc) · 3.29 KB
/
tapplicationserverbase_unix.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* Copyright (c) 2010-2019, AOYAMA Kazuharu
* All rights reserved.
*
* This software may be used and distributed according to the terms of
* the New BSD License, which is incorporated herein by reference.
*/
#include "tapplicationserverbase.h"
#include "tfcore_unix.h"
#include <QFile>
#include <QTcpServer>
#include <TSystemGlobal>
#include <cstring>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
void TApplicationServerBase::nativeSocketInit()
{
}
void TApplicationServerBase::nativeSocketCleanup()
{
}
/*!
Listen a port for connections on a socket.
This function must be called in a tfmanager process.
*/
int TApplicationServerBase::nativeListen(const QHostAddress &address, uint16_t port, OpenFlag flag)
{
int sd = 0;
QTcpServer server;
if (!server.listen(address, port)) {
tSystemError("Listen failed address:{} port:{}", qUtf8Printable(address.toString()), port);
return sd;
}
sd = duplicateSocket(server.socketDescriptor()); // duplicate
if (flag == CloseOnExec) {
::fcntl(sd, F_SETFD, ::fcntl(sd, F_GETFD) | FD_CLOEXEC);
} else {
::fcntl(sd, F_SETFD, 0); // clear
}
::fcntl(sd, F_SETFL, ::fcntl(sd, F_GETFL) | O_NONBLOCK); // non-block
int on = 1;
::setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); // TCP_NODELAY
#ifdef Q_OS_DARWIN
on = 1;
::setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on)); // NOSIGPIPE
#endif
server.close();
return sd;
}
/*!
Listen for connections on UNIX domain.
*/
int TApplicationServerBase::nativeListen(const QString &fileDomain, OpenFlag flag)
{
int sd = -1;
struct sockaddr_un addr;
std::memset(&addr, 0, sizeof(addr));
addr.sun_family = PF_UNIX;
if (sizeof(addr.sun_path) < (uint)fileDomain.toLatin1().size() + 1) {
tSystemError("too long name for UNIX domain socket [{}:{}]", __FILE__, __LINE__);
return sd;
}
std::strncpy(addr.sun_path, fileDomain.toLatin1().data(), sizeof(addr.sun_path) - 1);
// create unix domain socket
sd = ::socket(PF_UNIX, SOCK_STREAM, 0);
if (sd < 0) {
tSystemError("Socket create failed [{}:{}]", __FILE__, __LINE__);
return sd;
}
if (flag == CloseOnExec) {
::fcntl(sd, F_SETFD, FD_CLOEXEC); // set close-on-exec flag
}
::fcntl(sd, F_SETFL, ::fcntl(sd, F_GETFL) | O_NONBLOCK); // non-block
QFile file(fileDomain);
if (file.exists()) {
file.remove();
tSystemWarn("File for UNIX domain socket removed: {}", qUtf8Printable(fileDomain));
}
// Bind
if (::bind(sd, (sockaddr *)&addr, sizeof(sockaddr_un)) < 0) {
tSystemError("Bind failed [{}:{}]", __FILE__, __LINE__);
goto socket_error;
}
file.setPermissions((QFile::Permissions)0x777);
// Listen
if (::listen(sd, SOMAXCONN) < 0) {
tSystemError("Listen failed [{}:{}]", __FILE__, __LINE__);
goto socket_error;
}
return sd;
socket_error:
nativeClose(sd);
return -1;
}
void TApplicationServerBase::nativeClose(int socket)
{
if (socket > 0) {
tf_close_socket(socket);
}
}
int TApplicationServerBase::duplicateSocket(int socketDescriptor)
{
return ::fcntl(socketDescriptor, F_DUPFD, 0); // duplicate
}