|
15 | 15 | #include "TraceEvent.hpp"
|
16 | 16 | #include "Util.hpp"
|
17 | 17 |
|
| 18 | +#include <cerrno> |
18 | 19 | #include <chrono>
|
19 | 20 | #include <cstring>
|
20 | 21 | #include <cctype>
|
|
26 | 27 | #include <cstdio>
|
27 | 28 | #include <string>
|
28 | 29 | #include <unistd.h>
|
| 30 | +#include <sysexits.h> |
29 | 31 | #include <sys/stat.h>
|
30 | 32 | #include <sys/types.h>
|
31 | 33 | #include <sys/un.h>
|
@@ -1149,63 +1151,115 @@ bool ServerSocket::bind([[maybe_unused]] Type type, [[maybe_unused]] int port)
|
1149 | 1151 | #endif
|
1150 | 1152 | }
|
1151 | 1153 |
|
| 1154 | +bool ServerSocket::isUnrecoverableAcceptError(const int cause) |
| 1155 | +{ |
| 1156 | + constexpr const char * messagePrefix = "Failed to accept. (errno: "; |
| 1157 | + switch(cause) |
| 1158 | + { |
| 1159 | + case EINTR: |
| 1160 | + case EAGAIN: // == EWOULDBLOCK |
| 1161 | + case ENETDOWN: |
| 1162 | + case EPROTO: |
| 1163 | + case ENOPROTOOPT: |
| 1164 | + case EHOSTDOWN: |
| 1165 | +#ifdef ENONET |
| 1166 | + case ENONET: |
| 1167 | +#endif |
| 1168 | + case EHOSTUNREACH: |
| 1169 | + case EOPNOTSUPP: |
| 1170 | + case ENETUNREACH: |
| 1171 | + case ECONNABORTED: |
| 1172 | + case ETIMEDOUT: |
| 1173 | + case EMFILE: |
| 1174 | + case ENFILE: |
| 1175 | + case ENOMEM: |
| 1176 | + case ENOBUFS: |
| 1177 | + { |
| 1178 | + LOG_DBG(messagePrefix << std::to_string(cause) << ", " << std::strerror(cause) << ')'); |
| 1179 | + return false; |
| 1180 | + } |
| 1181 | + default: |
| 1182 | + { |
| 1183 | + LOG_FTL(messagePrefix << std::to_string(cause) << ", " << std::strerror(cause) << ')'); |
| 1184 | + return true; |
| 1185 | + } |
| 1186 | + } |
| 1187 | +} |
| 1188 | + |
1152 | 1189 | std::shared_ptr<Socket> ServerSocket::accept()
|
1153 | 1190 | {
|
1154 | 1191 | // Accept a connection (if any) and set it to non-blocking.
|
1155 | 1192 | // There still need the client's address to filter request from POST(call from REST) here.
|
1156 | 1193 | #if !MOBILEAPP
|
1157 | 1194 | assert(_type != Socket::Type::Unix);
|
1158 | 1195 |
|
| 1196 | + UnitWSD* const unitWsd = UnitWSD::isUnitTesting() ? &UnitWSD::get() : nullptr; |
| 1197 | + if (unitWsd && unitWsd->simulateExternalAcceptError()) |
| 1198 | + return nullptr; // Recoverable error, ignore to retry |
| 1199 | + |
1159 | 1200 | struct sockaddr_in6 clientInfo;
|
1160 | 1201 | socklen_t addrlen = sizeof(clientInfo);
|
1161 | 1202 | const int rc = ::accept4(getFD(), (struct sockaddr *)&clientInfo, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
1162 | 1203 | #else
|
1163 | 1204 | const int rc = fakeSocketAccept4(getFD());
|
1164 | 1205 | #endif
|
1165 |
| - LOG_TRC("Accepted socket #" << rc << ", creating socket object."); |
1166 |
| - try |
| 1206 | + if (rc < 0) |
1167 | 1207 | {
|
1168 |
| - // Create a socket object using the factory. |
1169 |
| - if (rc != -1) |
1170 |
| - { |
| 1208 | + if (isUnrecoverableAcceptError(errno)) |
| 1209 | + Util::forcedExit(EX_SOFTWARE); |
| 1210 | + return nullptr; |
| 1211 | + } |
| 1212 | + LOG_TRC("Accepted socket #" << rc << ", creating socket object."); |
| 1213 | + |
1171 | 1214 | #if !MOBILEAPP
|
1172 |
| - char addrstr[INET6_ADDRSTRLEN]; |
| 1215 | + char addrstr[INET6_ADDRSTRLEN]; |
1173 | 1216 |
|
1174 |
| - Socket::Type type; |
1175 |
| - const void *inAddr; |
1176 |
| - if (clientInfo.sin6_family == AF_INET) |
1177 |
| - { |
1178 |
| - struct sockaddr_in *ipv4 = (struct sockaddr_in *)&clientInfo; |
1179 |
| - inAddr = &(ipv4->sin_addr); |
1180 |
| - type = Socket::Type::IPv4; |
1181 |
| - } |
1182 |
| - else |
1183 |
| - { |
1184 |
| - struct sockaddr_in6 *ipv6 = &clientInfo; |
1185 |
| - inAddr = &(ipv6->sin6_addr); |
1186 |
| - type = Socket::Type::IPv6; |
1187 |
| - } |
| 1217 | + Socket::Type type; |
| 1218 | + const void *inAddr; |
| 1219 | + if (clientInfo.sin6_family == AF_INET) |
| 1220 | + { |
| 1221 | + struct sockaddr_in *ipv4 = (struct sockaddr_in *)&clientInfo; |
| 1222 | + inAddr = &(ipv4->sin_addr); |
| 1223 | + type = Socket::Type::IPv4; |
| 1224 | + } |
| 1225 | + else |
| 1226 | + { |
| 1227 | + struct sockaddr_in6 *ipv6 = &clientInfo; |
| 1228 | + inAddr = &(ipv6->sin6_addr); |
| 1229 | + type = Socket::Type::IPv6; |
| 1230 | + } |
| 1231 | + ::inet_ntop(clientInfo.sin6_family, inAddr, addrstr, sizeof(addrstr)); |
1188 | 1232 |
|
1189 |
| - std::shared_ptr<Socket> _socket = createSocketFromAccept(rc, type); |
| 1233 | + const size_t extConnCount = StreamSocket::getExternalConnectionCount(); |
| 1234 | + if (net::Defaults.maxExtConnections > 0 && extConnCount >= net::Defaults.maxExtConnections) |
| 1235 | + { |
| 1236 | + LOG_WRN("Limiter rejected extConn[" << extConnCount << "/" << net::Defaults.maxExtConnections << "]: #" |
| 1237 | + << rc << " has family " |
| 1238 | + << clientInfo.sin6_family << ", address " << addrstr << ":" << clientInfo.sin6_port); |
| 1239 | + ::close(rc); |
| 1240 | + return nullptr; |
| 1241 | + } |
| 1242 | + try |
| 1243 | + { |
| 1244 | + // Create a socket object using the factory. |
| 1245 | + std::shared_ptr<Socket> _socket = createSocketFromAccept(rc, type); |
| 1246 | + if (unitWsd) |
| 1247 | + unitWsd->simulateExternalSocketCtorException(_socket); |
1190 | 1248 |
|
1191 |
| - ::inet_ntop(clientInfo.sin6_family, inAddr, addrstr, sizeof(addrstr)); |
1192 |
| - _socket->setClientAddress(addrstr, clientInfo.sin6_port); |
| 1249 | + _socket->setClientAddress(addrstr, clientInfo.sin6_port); |
1193 | 1250 |
|
1194 |
| - LOG_TRC("Accepted socket #" << _socket->getFD() << " has family " |
1195 |
| - << clientInfo.sin6_family << ", " << *_socket); |
1196 |
| -#else |
1197 |
| - std::shared_ptr<Socket> _socket = createSocketFromAccept(rc, Socket::Type::Unix); |
1198 |
| -#endif |
1199 |
| - return _socket; |
1200 |
| - } |
1201 |
| - return std::shared_ptr<Socket>(nullptr); |
| 1251 | + LOG_TRC("Accepted socket #" << _socket->getFD() << " has family " |
| 1252 | + << clientInfo.sin6_family << ", " << *_socket); |
| 1253 | + return _socket; |
1202 | 1254 | }
|
1203 | 1255 | catch (const std::exception& ex)
|
1204 | 1256 | {
|
1205 | 1257 | LOG_ERR("Failed to create client socket #" << rc << ". Error: " << ex.what());
|
1206 | 1258 | }
|
1207 |
| - |
1208 | 1259 | return nullptr;
|
| 1260 | +#else |
| 1261 | + return createSocketFromAccept(rc, Socket::Type::Unix); |
| 1262 | +#endif |
1209 | 1263 | }
|
1210 | 1264 |
|
1211 | 1265 | #if !MOBILEAPP
|
@@ -1251,11 +1305,15 @@ bool Socket::isLocal() const
|
1251 | 1305 | std::shared_ptr<Socket> LocalServerSocket::accept()
|
1252 | 1306 | {
|
1253 | 1307 | const int rc = ::accept4(getFD(), nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
| 1308 | + if (rc < 0) |
| 1309 | + { |
| 1310 | + if (isUnrecoverableAcceptError(errno)) |
| 1311 | + Util::forcedExit(EX_SOFTWARE); |
| 1312 | + return nullptr; |
| 1313 | + } |
1254 | 1314 | try
|
1255 | 1315 | {
|
1256 | 1316 | LOG_DBG("Accepted prisoner socket #" << rc << ", creating socket object.");
|
1257 |
| - if (rc < 0) |
1258 |
| - return std::shared_ptr<Socket>(nullptr); |
1259 | 1317 |
|
1260 | 1318 | std::shared_ptr<Socket> _socket = createSocketFromAccept(rc, Socket::Type::Unix);
|
1261 | 1319 | // Sanity check this incoming socket
|
@@ -1305,8 +1363,8 @@ std::shared_ptr<Socket> LocalServerSocket::accept()
|
1305 | 1363 | catch (const std::exception& ex)
|
1306 | 1364 | {
|
1307 | 1365 | LOG_ERR("Failed to create client socket #" << rc << ". Error: " << ex.what());
|
1308 |
| - return std::shared_ptr<Socket>(nullptr); |
1309 | 1366 | }
|
| 1367 | + return nullptr; |
1310 | 1368 | }
|
1311 | 1369 |
|
1312 | 1370 | /// Returns true on success only.
|
|
0 commit comments