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