Skip to content

Commit 923a8ec

Browse files
committed
Use socketpair() to create sockets
1 parent 2ae7dd5 commit 923a8ec

5 files changed

Lines changed: 32 additions & 89 deletions

File tree

src/program/GameLoop.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include <sys/stat.h> // stat
5353
#include <sys/wait.h> // waitpid
5454
// #include <X11/X.h>
55+
#include <sys/socket.h>
5556
#include <stdint.h>
5657

5758
GameLoop::GameLoop(Context* c) : movie(MovieFile(c)), context(c)
@@ -183,20 +184,29 @@ void GameLoop::init()
183184
/* Remove savestates again in case we did not exist cleanly the previous time */
184185
remove_savestates(context);
185186

186-
/* Remove the file socket */
187-
int err = removeSocket();
188-
if (err != 0)
189-
emit alertToShow(QString("Could not remove socket file /tmp/libTAS.socket: %2").arg(strerror(err)));
190-
191187
/* Init savestate list */
192188
SaveStateList::init(context);
193189

190+
/* Create socket pair */
191+
int sockets[2];
192+
193+
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
194+
perror("Failed to create socket pair");
195+
return;
196+
}
197+
194198
/* We fork here so that the child process calls the game */
195199
context->fork_pid = fork();
196200
if (context->fork_pid == 0) {
197-
GameThread::launch(context);
201+
close(sockets[0]);
202+
203+
// noreturn; calls exec
204+
return GameThread::launch(context, sockets[1]);
198205
}
199206

207+
close(sockets[1]);
208+
setSocket(sockets[0]);
209+
200210
/* Compute the MD5 hash of the game binary */
201211
context->md5_game.clear();
202212
std::ostringstream cmd;
@@ -267,9 +277,6 @@ void GameLoop::init()
267277

268278
void GameLoop::initProcessMessages()
269279
{
270-
/* Connect to the socket between the program and the game */
271-
initSocketProgram();
272-
273280
/* Receive informations from the game */
274281
int message = receiveMessage();
275282
while (message != MSGB_END_INIT) {
@@ -739,7 +746,6 @@ void GameLoop::loopExit()
739746
(context->status != Context::QUITTING))) {
740747

741748
/* We keep the movie opened and indicate the main thread to restart the game */
742-
743749
closeSocket();
744750

745751
/* Remove savestates because they are invalid on future instances of the game */

src/program/GameThread.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#include <unistd.h> // chdir()
3333
#include <fcntl.h> // O_RDWR, O_CREAT
3434

35-
void GameThread::launch(Context *context)
35+
void GameThread::launch(Context *context, int sock)
3636
{
3737
#ifdef __unix__
3838
/* Update the LD_LIBRARY_PATH environment variable if the user set one */
@@ -120,6 +120,9 @@ void GameThread::launch(Context *context)
120120
/* Override timezone for determinism */
121121
setenv("TZ", "UTC0", 1);
122122

123+
/* Pass socket file descriptor to the game */
124+
setenv("LIBTAS_SOCKET_FD", std::to_string(sock).c_str(), 1);
125+
123126
/* Build the argument list to be fed to execv */
124127
std::list<std::string> arg_list;
125128

src/program/GameThread.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace GameThread {
2828
* Because this function eventually calls execl, it does not return.
2929
* So, it is called from a child process using fork().
3030
*/
31-
void launch(Context *context);
31+
void launch(Context *context, int sock);
3232
}
3333

3434
#endif

src/shared/sockethelpers.cpp

Lines changed: 9 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919

2020
#include "sockethelpers.h"
2121
#include <sys/socket.h>
22-
#include <sys/stat.h>
2322
#include <cstdlib>
2423
#include <unistd.h>
2524
#include <sys/un.h>
2625
#include <iostream>
2726
#include <vector>
2827
#include <mutex>
2928
#include <errno.h>
29+
#include <fcntl.h>
3030

3131
#ifdef SOCKET_LOG
3232
#include "lcf.h"
@@ -35,8 +35,6 @@
3535
#include <iostream>
3636
#endif
3737

38-
#define SOCKET_FILENAME "/tmp/libTAS.socket"
39-
4038
#ifndef MSG_NOSIGNAL
4139
#define MSG_NOSIGNAL 0
4240
#endif
@@ -48,80 +46,20 @@ static int socket_fd = 0;
4846

4947
static std::mutex mutex;
5048

51-
int removeSocket(void) {
52-
int ret = unlink(SOCKET_FILENAME);
53-
if ((ret == -1) && (errno != ENOENT))
54-
return errno;
55-
return 0;
49+
void setSocket(int sock) {
50+
socket_fd = sock;
5651
}
5752

58-
bool initSocketProgram(void)
53+
bool initSocketGame(void)
5954
{
60-
#ifdef __unix__
61-
const struct sockaddr_un addr = { AF_UNIX, SOCKET_FILENAME };
62-
#elif defined(__APPLE__) && defined(__MACH__)
63-
const struct sockaddr_un addr = { sizeof(struct sockaddr_un), AF_UNIX, SOCKET_FILENAME };
64-
#endif
65-
socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
55+
socket_fd = std::stoi(getenv("LIBTAS_SOCKET_FD"));
6656

67-
struct timespec tim = {0, 500L*1000L*1000L};
68-
69-
const int MAX_RETRIES = 10;
70-
int retry = 0;
71-
72-
nanosleep(&tim, NULL);
73-
while (connect(socket_fd, reinterpret_cast<const struct sockaddr*>(&addr),
74-
sizeof(struct sockaddr_un))) {
75-
std::cout << "Attempt " << retry + 1 << ": Couldn't connect to socket." << std::endl;
76-
retry++;
77-
if (retry < MAX_RETRIES) {
78-
nanosleep(&tim, NULL);
57+
if (fcntl(socket_fd, F_GETFD) == -1) {
58+
if (errno == EBADF) {
59+
perror("LIBTAS_SOCKET_FD has been closed");
7960
} else {
80-
return false;
81-
}
82-
tim.tv_nsec *= 1.5;
83-
if (tim.tv_nsec >= 1000000000) {
84-
tim.tv_sec++;
85-
tim.tv_nsec -= 1000000000;
61+
perror("Unable to use game socket");
8662
}
87-
}
88-
std::cout << "Attempt " << retry + 1 << ": Connected." << std::endl;
89-
90-
return true;
91-
}
92-
93-
bool initSocketGame(void)
94-
{
95-
/* Check if socket file already exists. If so, it is probably because
96-
* the link is already done in another process of the game.
97-
* In this case, we just return immediately.
98-
*/
99-
struct stat st;
100-
int result = stat(SOCKET_FILENAME, &st);
101-
if (result == 0)
102-
return false;
103-
104-
#ifdef __unix__
105-
const struct sockaddr_un addr = { AF_UNIX, SOCKET_FILENAME };
106-
#elif defined(__APPLE__) && defined(__MACH__)
107-
const struct sockaddr_un addr = { sizeof(struct sockaddr_un), AF_UNIX, SOCKET_FILENAME };
108-
#endif
109-
const int tmp_fd = socket(AF_UNIX, SOCK_STREAM, 0);
110-
if (bind(tmp_fd, reinterpret_cast<const struct sockaddr*>(&addr), sizeof(struct sockaddr_un)))
111-
{
112-
std::cerr << "Couldn't bind client socket." << std::endl;
113-
exit(-1);
114-
}
115-
116-
if (listen(tmp_fd, 1))
117-
{
118-
std::cerr << "Couldn't listen on client socket." << std::endl;
119-
exit(-1);
120-
}
121-
122-
if ((socket_fd = accept(tmp_fd, NULL, NULL)) < 0)
123-
{
124-
std::cerr << "Couldn't accept client connection." << std::endl;
12563
exit(-1);
12664
}
12765

@@ -135,7 +73,6 @@ bool initSocketGame(void)
13573
}
13674
#endif
13775

138-
close(tmp_fd);
13976
return true;
14077
}
14178

src/shared/sockethelpers.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,8 @@
2323
#include <cstddef>
2424
#include <string>
2525

26-
/* Remove the socket file and return error */
27-
int removeSocket();
28-
29-
/* Initiate a socket connection with the game */
30-
bool initSocketProgram(void);
26+
/* Sets socket_fd */
27+
void setSocket(int sock);
3128

3229
/* Initiate a socket connection with libTAS */
3330
bool initSocketGame(void);

0 commit comments

Comments
 (0)