CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/File/FileDescriptor.cpp
Views: 1401
1
#include "ppsspp_config.h"
2
3
#include <errno.h>
4
#include <cmath>
5
#include <cstdio>
6
#ifndef _WIN32
7
#include <arpa/inet.h>
8
#include <netinet/in.h>
9
#include <sys/socket.h>
10
#include <sys/types.h>
11
#include <sys/select.h>
12
#include <unistd.h>
13
#else
14
#include <io.h>
15
#include <winsock2.h>
16
#include <ws2tcpip.h>
17
#endif
18
#include <fcntl.h>
19
20
#include "Common/CommonTypes.h"
21
#include "Common/Data/Encoding/Utf8.h"
22
#include "Common/File/FileDescriptor.h"
23
#include "Common/Log.h"
24
25
namespace fd_util {
26
27
// Slow as hell and should only be used for prototyping.
28
// Reads from a socket, up to an '\n'. This means that if the line ends
29
// with '\r', the '\r' will be returned.
30
size_t ReadLine(int fd, char *vptr, size_t buf_size) {
31
char *buffer = vptr;
32
size_t n;
33
for (n = 1; n < buf_size; n++) {
34
char c;
35
size_t rc;
36
if ((rc = read(fd, &c, 1)) == 1) {
37
*buffer++ = c;
38
if (c == '\n')
39
break;
40
} else if (rc == 0) {
41
if (n == 1)
42
return 0;
43
else
44
break;
45
} else {
46
if (errno == EINTR)
47
continue;
48
_assert_msg_(false, "Error in Readline()");
49
}
50
}
51
52
*buffer = 0;
53
return n;
54
}
55
56
// Misnamed, it just writes raw data in a retry loop.
57
size_t WriteLine(int fd, const char *vptr, size_t n) {
58
const char *buffer = vptr;
59
size_t nleft = n;
60
61
while (nleft > 0) {
62
int nwritten;
63
if ((nwritten = (int)write(fd, buffer, (unsigned int)nleft)) <= 0) {
64
if (errno == EINTR)
65
nwritten = 0;
66
else
67
_assert_msg_(false, "Error in Writeline()");
68
}
69
nleft -= nwritten;
70
buffer += nwritten;
71
}
72
73
return n;
74
}
75
76
size_t WriteLine(int fd, const char *buffer) {
77
return WriteLine(fd, buffer, strlen(buffer));
78
}
79
80
size_t Write(int fd, const std::string &str) {
81
return WriteLine(fd, str.c_str(), str.size());
82
}
83
84
bool WaitUntilReady(int fd, double timeout, bool for_write) {
85
struct timeval tv;
86
tv.tv_sec = (long)floor(timeout);
87
tv.tv_usec = (long)((timeout - floor(timeout)) * 1000000.0);
88
89
fd_set fds;
90
FD_ZERO(&fds);
91
FD_SET(fd, &fds);
92
// First argument to select is the highest socket in the set + 1.
93
int rval;
94
if (for_write) {
95
rval = select(fd + 1, nullptr, &fds, nullptr, &tv);
96
} else {
97
rval = select(fd + 1, &fds, nullptr, nullptr, &tv);
98
}
99
100
if (rval < 0) {
101
// Error calling select.
102
return false;
103
} else if (rval == 0) {
104
// Timeout.
105
return false;
106
} else {
107
// Socket is ready.
108
return true;
109
}
110
}
111
112
void SetNonBlocking(int sock, bool non_blocking) {
113
#ifndef _WIN32
114
int opts = fcntl(sock, F_GETFL);
115
if (opts < 0) {
116
perror("fcntl(F_GETFL)");
117
ERROR_LOG(Log::IO, "Error getting socket status while changing nonblocking status");
118
}
119
if (non_blocking) {
120
opts = (opts | O_NONBLOCK);
121
} else {
122
opts = (opts & ~O_NONBLOCK);
123
}
124
125
if (fcntl(sock, F_SETFL, opts) < 0) {
126
perror("fcntl(F_SETFL)");
127
ERROR_LOG(Log::IO, "Error setting socket nonblocking status");
128
}
129
#else
130
u_long val = non_blocking ? 1 : 0;
131
if (ioctlsocket(sock, FIONBIO, &val) != 0) {
132
ERROR_LOG(Log::IO, "Error setting socket nonblocking status");
133
}
134
#endif
135
}
136
137
std::string GetLocalIP(int sock) {
138
union {
139
struct sockaddr sa;
140
struct sockaddr_in ipv4;
141
#if !PPSSPP_PLATFORM(SWITCH)
142
struct sockaddr_in6 ipv6;
143
#endif
144
} server_addr;
145
memset(&server_addr, 0, sizeof(server_addr));
146
socklen_t len = sizeof(server_addr);
147
if (getsockname(sock, (struct sockaddr *)&server_addr, &len) == 0) {
148
char temp[64]{};
149
150
// We clear the port below for WSAAddressToStringA.
151
void *addr = nullptr;
152
#if !PPSSPP_PLATFORM(SWITCH)
153
if (server_addr.sa.sa_family == AF_INET6) {
154
server_addr.ipv6.sin6_port = 0;
155
addr = &server_addr.ipv6.sin6_addr;
156
}
157
#endif
158
if (addr == nullptr) {
159
server_addr.ipv4.sin_port = 0;
160
addr = &server_addr.ipv4.sin_addr;
161
}
162
#ifdef _WIN32
163
wchar_t wtemp[sizeof(temp)];
164
DWORD len = (DWORD)sizeof(temp);
165
// Windows XP doesn't support inet_ntop.
166
if (WSAAddressToStringW((struct sockaddr *)&server_addr, sizeof(server_addr), nullptr, wtemp, &len) == 0) {
167
return ConvertWStringToUTF8(wtemp);
168
}
169
#else
170
const char *result = inet_ntop(server_addr.sa.sa_family, addr, temp, sizeof(temp));
171
if (result) {
172
return result;
173
}
174
#endif
175
}
176
return "";
177
}
178
179
} // fd_util
180
181