Skip to content

Commit 3a71b20

Browse files
Copilotclauspruefer
andcommitted
Replace pidfd_getfd with Unix domain socket for FD passing
Co-authored-by: clauspruefer <17313789+clauspruefer@users.noreply.github.com>
1 parent ad5e010 commit 3a71b20

6 files changed

Lines changed: 247 additions & 17 deletions

File tree

src/ASProcessHandler.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,11 @@ void ASProcessHandler::forkProcessASHandler(ASProcessHandlerSHMPointer_t SHMAdre
119119
ERR("Cannot change dir to BackendRootPath Path:" << BackendRootPath.c_str());
120120
}
121121

122-
//- get parent pid filedescriptor
123-
pidfd_t ParentPidFD = Syscall::pidfd_open(getppid(), 0);
124-
125122
const char* Env1 = std::getenv("PATH");
126123
const char* Env2 = std::getenv("PYTHONPATH");
127124

128125
DBG(120, "Process PATH:" << Env1 << " PYTHONPATH:" << Env2);
129-
DBG(200, "Child ASProcessHandler Process PID:" << getpid() << " ParentPidFD:" << ParentPidFD);
126+
DBG(200, "Child ASProcessHandler Process PID:" << getpid());
130127

131128
//- initialize backend
132129
Backend::Processor::init(this);

src/Global.hpp

Lines changed: 111 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33

44
#include <csignal>
55
#include <string>
6+
#include <cstring>
67
#include <unordered_map>
78
#include <vector>
89
#include <exception>
910
#include <cstdlib>
1011

1112
#include <sys/syscall.h>
13+
#include <sys/socket.h>
14+
#include <sys/un.h>
1215
#include <unistd.h>
1316
#include <execinfo.h>
1417

@@ -19,7 +22,6 @@ using namespace std;
1922

2023

2124
typedef unsigned int Filedescriptor_t;
22-
typedef unsigned int pidfd_t;
2325

2426
typedef uint16_t HTTPVersionType_t;
2527
typedef uint16_t HTTPMethodType_t;
@@ -67,16 +69,118 @@ class Syscall {
6769

6870
public:
6971

70-
//- wrapper function for pidfd_open
71-
static int pidfd_open(pid_t pid, unsigned int flags)
72+
//- Unix domain socket for FD passing - server side (parent process)
73+
static int createFDPassingServer(const char* socket_path)
7274
{
73-
return syscall(SYS_pidfd_open, pid, flags);
75+
int server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
76+
if (server_fd < 0) {
77+
return -1;
78+
}
79+
80+
// Remove any existing socket file
81+
unlink(socket_path);
82+
83+
struct sockaddr_un server_addr;
84+
memset(&server_addr, 0, sizeof(server_addr));
85+
server_addr.sun_family = AF_UNIX;
86+
strncpy(server_addr.sun_path, socket_path, sizeof(server_addr.sun_path) - 1);
87+
88+
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
89+
close(server_fd);
90+
return -1;
91+
}
92+
93+
if (listen(server_fd, 50) < 0) {
94+
close(server_fd);
95+
return -1;
96+
}
97+
98+
return server_fd;
7499
}
75100

76-
//- wrapper function for pidfd_getfd
77-
static int pidfd_getfd(int pidfd, int targetfd, unsigned int flags)
101+
//- Unix domain socket for FD passing - client side (child process)
102+
static int connectFDPassingClient(const char* socket_path)
78103
{
79-
return syscall(SYS_pidfd_getfd, pidfd, targetfd, flags);
104+
int client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
105+
if (client_fd < 0) {
106+
return -1;
107+
}
108+
109+
struct sockaddr_un server_addr;
110+
memset(&server_addr, 0, sizeof(server_addr));
111+
server_addr.sun_family = AF_UNIX;
112+
strncpy(server_addr.sun_path, socket_path, sizeof(server_addr.sun_path) - 1);
113+
114+
if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
115+
close(client_fd);
116+
return -1;
117+
}
118+
119+
return client_fd;
120+
}
121+
122+
//- Send a file descriptor over Unix domain socket
123+
static int sendFD(int socket_fd, int fd_to_send)
124+
{
125+
struct msghdr msg;
126+
struct iovec iov[1];
127+
char ctrl_buf[CMSG_SPACE(sizeof(int))];
128+
char data[1] = {0};
129+
130+
memset(&msg, 0, sizeof(msg));
131+
memset(ctrl_buf, 0, sizeof(ctrl_buf));
132+
133+
// Setup iovec for dummy data
134+
iov[0].iov_base = data;
135+
iov[0].iov_len = sizeof(data);
136+
137+
msg.msg_iov = iov;
138+
msg.msg_iovlen = 1;
139+
msg.msg_control = ctrl_buf;
140+
msg.msg_controllen = sizeof(ctrl_buf);
141+
142+
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
143+
cmsg->cmsg_level = SOL_SOCKET;
144+
cmsg->cmsg_type = SCM_RIGHTS;
145+
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
146+
*((int*)CMSG_DATA(cmsg)) = fd_to_send;
147+
148+
if (sendmsg(socket_fd, &msg, 0) < 0) {
149+
return -1;
150+
}
151+
152+
return 0;
153+
}
154+
155+
//- Receive a file descriptor over Unix domain socket
156+
static int recvFD(int socket_fd)
157+
{
158+
struct msghdr msg;
159+
struct iovec iov[1];
160+
char ctrl_buf[CMSG_SPACE(sizeof(int))];
161+
char data[1];
162+
163+
memset(&msg, 0, sizeof(msg));
164+
memset(ctrl_buf, 0, sizeof(ctrl_buf));
165+
166+
iov[0].iov_base = data;
167+
iov[0].iov_len = sizeof(data);
168+
169+
msg.msg_iov = iov;
170+
msg.msg_iovlen = 1;
171+
msg.msg_control = ctrl_buf;
172+
msg.msg_controllen = sizeof(ctrl_buf);
173+
174+
if (recvmsg(socket_fd, &msg, 0) < 0) {
175+
return -1;
176+
}
177+
178+
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
179+
if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS) {
180+
return -1;
181+
}
182+
183+
return *((int*)CMSG_DATA(cmsg));
80184
}
81185

82186
};

src/ResultProcessor.cpp

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,26 @@ void ResultProcessor::terminate(int _ignored)
2929
RunServer = false;
3030
}
3131

32+
int ResultProcessor::_getFDFromParent(uint16_t fd)
33+
{
34+
// Send the requested FD number to the parent
35+
if (write(_FDPassingSocketFD, &fd, sizeof(fd)) != sizeof(fd)) {
36+
ERR("Failed to send FD request to parent");
37+
return -1;
38+
}
39+
40+
// Receive the FD from the parent
41+
int received_fd = Syscall::recvFD(_FDPassingSocketFD);
42+
43+
if (received_fd < 0) {
44+
ERR("Failed to receive FD from parent");
45+
return -1;
46+
}
47+
48+
DBG(120, "Received FD:" << received_fd << " from parent for requested FD:" << fd);
49+
return received_fd;
50+
}
51+
3252
void ResultProcessor::setVHostOffsets(VHostOffsetsPrecalc_t VHostOffsets) {
3353
_VHostOffsetsPrecalc = VHostOffsets;
3454
}
@@ -56,16 +76,24 @@ pid_t ResultProcessor::forkProcessResultProcessor(ResultProcessorSHMPointer_t SH
5676

5777
if (_ForkResult == 0) {
5878

59-
//- get parent pid filedescriptor
60-
_ParentPidFD = Syscall::pidfd_open(getppid(), 0);
79+
//- connect to parent's FD passing server
80+
const char* socket_path = "/tmp/falcon-fd-passing.sock";
81+
_FDPassingSocketFD = Syscall::connectFDPassingClient(socket_path);
82+
83+
if (_FDPassingSocketFD < 0) {
84+
ERR("ResultProcessor: Failed to connect to FD passing server");
85+
exit(1);
86+
}
87+
88+
DBG(120, "ResultProcessor: Connected to FD passing server");
6189

6290
//- overwrite parent termination handler
6391
setTerminationHandler();
6492

6593
//- spectre userspace protection
6694
prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_ENABLE, 0, 0);
6795

68-
DBG(120, "Child ResultProcessor Process PID:" << getpid() << " ParentPidFD:" << _ParentPidFD);
96+
DBG(120, "Child ResultProcessor Process PID:" << getpid() << " FDPassingSocketFD:" << _FDPassingSocketFD);
6997
DBG(120, "Child ResultProcessor SharedMemAddress:" << SHMAdresses.StaticFSPtr);
7098
DBG(120, "Child ResultProcessor Atomic Address:" << StaticFSLock << " Value:" << *(StaticFSLock));
7199

@@ -151,7 +179,7 @@ void ResultProcessor::_processStaticFSRequests(uint16_t RequestCount)
151179
getNextAddress(ClientPayloadLength);
152180
DBG(120, "ClientFD:" << ClientFD << " ReqNr:" << ReqNr << " HTTPVersion:" << HTTPVersion << " PayloadLength:" << ClientPayloadLength << " Payload:'" << ClientPayloadString << "'");
153181

154-
ClientFD_t ClientFDShared = Syscall::pidfd_getfd(_ParentPidFD, ClientFD, 0);
182+
ClientFD_t ClientFDShared = _getFDFromParent(ClientFD);
155183

156184
RequestProps_t Request;
157185

@@ -182,7 +210,7 @@ uint16_t ResultProcessor::_processPythonASResults()
182210
RequestProps_t Request;
183211

184212
Request.ClientFD = *(static_cast<ClientFD_t*>(getMetaAddress(Index, 2)));
185-
Request.ClientFDShared = Syscall::pidfd_getfd(_ParentPidFD, Request.ClientFD, 0);
213+
Request.ClientFDShared = _getFDFromParent(Request.ClientFD);
186214
Request.HTTPVersion = *(static_cast<HTTPVersionType_t*>(getMetaAddress(Index, 3)));
187215
Request.PayloadLength = *(static_cast<HTTPPayloadLength_t*>(getMetaAddress(Index, 7)));
188216

src/ResultProcessor.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ class ResultProcessor : private SHMStaticFS, public CPU, private ResultOrder, pr
4343
void _processStaticFSRequests(uint16_t);
4444
inline void _parseHTTPBaseProps(string&);
4545
uint16_t _processPythonASResults();
46+
int _getFDFromParent(uint16_t fd);
4647

4748
pid_t _ForkResult;
48-
pidfd_t _ParentPidFD;
49+
int _FDPassingSocketFD;
4950
VHostOffsetsPrecalc_t _VHostOffsetsPrecalc;
5051

5152
};

src/Server.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ void Server::init()
3232
setupSharedMemory();
3333
setSharedMemPointer( { _SHMStaticFS, _SHMPythonASMeta, _SHMPythonASRequests, _SHMPythonASResults } );
3434

35+
//- setup FD passing server
36+
setupFDPassingServer();
37+
3538
//- init static filesystem
3639
ConfigRef.mapStaticFSData();
3740

@@ -248,3 +251,95 @@ void Server::setupSharedMemory()
248251

249252
DBG(120, "SharedMemAddress:" << _SHMStaticFS);
250253
}
254+
255+
void Server::setupFDPassingServer()
256+
{
257+
DBG(120, "Setup FD Passing Server.");
258+
259+
const char* socket_path = "/tmp/falcon-fd-passing.sock";
260+
_FDPassingServerFD = Syscall::createFDPassingServer(socket_path);
261+
262+
if (_FDPassingServerFD < 0) {
263+
ERR("Failed to create FD passing server socket");
264+
exit(EXIT_FAILURE);
265+
}
266+
267+
DBG(120, "FD Passing Server socket created at:" << socket_path);
268+
269+
// Start thread to handle FD passing requests
270+
_FDPassingThread = std::thread(&Server::handleFDPassingRequests, this);
271+
}
272+
273+
void Server::handleFDPassingRequests()
274+
{
275+
DBG(120, "FD Passing handler thread started");
276+
277+
// Set socket to non-blocking
278+
int flags = fcntl(_FDPassingServerFD, F_GETFL, 0);
279+
fcntl(_FDPassingServerFD, F_SETFL, flags | O_NONBLOCK);
280+
281+
std::vector<int> client_fds;
282+
283+
while(RunServer) {
284+
// Accept new connections
285+
struct sockaddr_un client_addr;
286+
socklen_t client_len = sizeof(client_addr);
287+
288+
int new_client_fd = accept(_FDPassingServerFD, (struct sockaddr*)&client_addr, &client_len);
289+
290+
if (new_client_fd >= 0) {
291+
DBG(120, "FD passing new client connected, fd:" << new_client_fd);
292+
client_fds.push_back(new_client_fd);
293+
}
294+
295+
// Process existing connections
296+
auto it = client_fds.begin();
297+
while (it != client_fds.end()) {
298+
int client_fd = *it;
299+
uint16_t requested_fd;
300+
301+
ssize_t n = read(client_fd, &requested_fd, sizeof(requested_fd));
302+
303+
if (n == sizeof(requested_fd)) {
304+
DBG(120, "FD passing request for FD:" << requested_fd);
305+
306+
// Send the requested FD to the client
307+
if (Syscall::sendFD(client_fd, requested_fd) < 0) {
308+
ERR("Failed to send FD:" << requested_fd);
309+
close(client_fd);
310+
it = client_fds.erase(it);
311+
} else {
312+
DBG(120, "Successfully sent FD:" << requested_fd);
313+
++it;
314+
}
315+
} else if (n == 0) {
316+
// Connection closed
317+
DBG(120, "FD passing client disconnected, fd:" << client_fd);
318+
close(client_fd);
319+
it = client_fds.erase(it);
320+
} else if (n < 0) {
321+
if (errno != EAGAIN && errno != EWOULDBLOCK) {
322+
ERR("Failed to read requested FD number:" << strerror(errno));
323+
close(client_fd);
324+
it = client_fds.erase(it);
325+
} else {
326+
++it;
327+
}
328+
} else {
329+
// Partial read - shouldn't happen with small fixed-size data
330+
ERR("Partial read of FD request");
331+
close(client_fd);
332+
it = client_fds.erase(it);
333+
}
334+
}
335+
336+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
337+
}
338+
339+
// Clean up
340+
for (int fd : client_fds) {
341+
close(fd);
342+
}
343+
344+
DBG(120, "FD Passing handler thread exiting");
345+
}

src/Server.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class Server : private ResultProcessor, private ASProcessHandler, private Client
3636
static void terminate(int);
3737

3838
void setupSharedMemory();
39+
void setupFDPassingServer();
40+
void handleFDPassingRequests();
3941

4042
static void addChildPID(pid_t);
4143
static void terminateChildren();
@@ -57,6 +59,9 @@ class Server : private ResultProcessor, private ASProcessHandler, private Client
5759
void* _SHMPythonASRequests;
5860
void* _SHMPythonASResults;
5961

62+
int _FDPassingServerFD;
63+
std::thread _FDPassingThread;
64+
6065
static std::vector<pid_t> ChildPIDs;
6166

6267
};

0 commit comments

Comments
 (0)