Verbessere Socket-Validierung und Fehlerbehandlung in ChatUser und Base

- Füge Überprüfungen hinzu, um sicherzustellen, dass der Socket gültig ist, bevor Nachrichten gesendet werden.
- Implementiere detaillierte Fehlerprotokollierung für verschiedene Socket-Fehler, um die Diagnose zu erleichtern.
- Ergänze eine kurze Verzögerung im ChatRoom, um den Abschluss des WebSocket-Handshakes zu gewährleisten.
This commit is contained in:
Torsten Schulz (local)
2025-09-05 10:42:23 +02:00
parent dce5a56316
commit 411a4c52c7
3 changed files with 89 additions and 2 deletions

View File

@@ -128,6 +128,9 @@ namespace Yc
newUser->sendMsg(ChatUser::roomList, roomList, "", ""); newUser->sendMsg(ChatUser::roomList, roomList, "", "");
} }
// Kurze Pause, damit der WebSocket-Handshake vollständig abgeschlossen ist
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// Sende aktuelle Userliste an den neuen User // Sende aktuelle Userliste an den neuen User
Json::Value currentUserList = userList(); Json::Value currentUserList = userList();
newUser->sendMsg(ChatUser::userListe, currentUserList, "", ""); newUser->sendMsg(ChatUser::userListe, currentUserList, "", "");

View File

@@ -8,6 +8,7 @@
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <fcntl.h>
#include "chat_room.h" #include "chat_room.h"
#include <iostream> #include <iostream>
#include <netinet/in.h> #include <netinet/in.h>
@@ -336,6 +337,8 @@ namespace Yc
void ChatUser::stop() void ChatUser::stop()
{ {
_stop = true; _stop = true;
// Socket als ungültig markieren
_socket = -1;
} }
std::string ChatUser::color() const std::string ChatUser::color() const
@@ -349,12 +352,38 @@ namespace Yc
} }
void ChatUser::send(std::string out) { void ChatUser::send(std::string out) {
// Prüfe ob Socket noch gültig ist
if (_socket < 0 || _stop) {
#ifdef YC_DEBUG
std::cout << "[Debug] Skipping send - socket invalid or user stopped" << std::endl;
#endif
return;
}
// Zusätzliche Socket-Validierung mit fcntl
int flags = fcntl(_socket, F_GETFL);
if (flags == -1) {
#ifdef YC_DEBUG
std::cout << "[Debug] Socket " << _socket << " is invalid (fcntl failed), skipping send" << std::endl;
#endif
_socket = -1; // Markiere als ungültig
return;
}
// Entferne ggf. Token-Felder aus JSON-Strings und sende über Socket/WebSocket // Entferne ggf. Token-Felder aus JSON-Strings und sende über Socket/WebSocket
Base::sanitizeTokensInString(out); Base::sanitizeTokensInString(out);
Base::send(_socket, out); Base::send(_socket, out);
} }
void ChatUser::send(Json::Value out) { void ChatUser::send(Json::Value out) {
// Prüfe ob Socket noch gültig ist
if (_socket < 0 || _stop) {
#ifdef YC_DEBUG
std::cout << "[Debug] Skipping send - socket invalid or user stopped" << std::endl;
#endif
return;
}
// Entferne rekursiv alle Token-Felder und sende über Socket/WebSocket // Entferne rekursiv alle Token-Felder und sende über Socket/WebSocket
Base::sanitizeTokens(out); Base::sanitizeTokens(out);
Base::send(_socket, out); Base::send(_socket, out);

View File

@@ -64,9 +64,35 @@ namespace Yc {
sendWebSocketMessage(socket, out); sendWebSocketMessage(socket, out);
return; return;
} }
// Socket-Validierung vor dem Senden
if (socket < 0) {
#ifdef YC_DEBUG
std::cout << "[Debug] Invalid socket (< 0), skipping send" << std::endl;
#endif
return;
}
ssize_t result = write(socket, out.c_str(), out.length()); ssize_t result = write(socket, out.c_str(), out.length());
if (result < 0) { if (result < 0) {
std::cout << "[Error] Fehler beim Senden auf Socket (vermutlich Verbindung verloren): " << strerror(errno) << std::endl; int error = errno;
// Nur kritische Fehler loggen, nicht alle "Bad file descriptor" Fehler
if (error == EBADF) {
#ifdef YC_DEBUG
std::cout << "[Debug] Socket " << socket << " closed by client, skipping send" << std::endl;
#endif
} else if (error == EPIPE) {
#ifdef YC_DEBUG
std::cout << "[Debug] Broken pipe on socket " << socket << ", connection closed" << std::endl;
#endif
} else if (error == ECONNRESET) {
#ifdef YC_DEBUG
std::cout << "[Debug] Connection reset by peer on socket " << socket << std::endl;
#endif
} else {
// Nur unbekannte Fehler als Error loggen
std::cout << "[Error] Fehler beim Senden auf Socket " << socket << ": " << strerror(error) << std::endl;
}
} }
} }
@@ -209,6 +235,14 @@ namespace Yc {
} }
void Base::sendWebSocketMessage(int socket, const std::string& out) { void Base::sendWebSocketMessage(int socket, const std::string& out) {
// Socket-Validierung vor dem Senden
if (socket < 0) {
#ifdef YC_DEBUG
std::cout << "[Debug] Invalid WebSocket socket (< 0), skipping send" << std::endl;
#endif
return;
}
std::string frame; std::string frame;
unsigned char hdr[2]; unsigned char hdr[2];
hdr[0] = 0x80 | 0x1; // FIN + text hdr[0] = 0x80 | 0x1; // FIN + text
@@ -230,7 +264,28 @@ namespace Yc {
frame.append(reinterpret_cast<char*>(ext), 8); frame.append(reinterpret_cast<char*>(ext), 8);
} }
frame.append(out); frame.append(out);
::send(socket, frame.data(), frame.size(), 0);
ssize_t result = ::send(socket, frame.data(), frame.size(), 0);
if (result < 0) {
int error = errno;
// Nur kritische Fehler loggen, nicht alle "Bad file descriptor" Fehler
if (error == EBADF) {
#ifdef YC_DEBUG
std::cout << "[Debug] WebSocket " << socket << " closed by client, skipping send" << std::endl;
#endif
} else if (error == EPIPE) {
#ifdef YC_DEBUG
std::cout << "[Debug] Broken pipe on WebSocket " << socket << ", connection closed" << std::endl;
#endif
} else if (error == ECONNRESET) {
#ifdef YC_DEBUG
std::cout << "[Debug] Connection reset by peer on WebSocket " << socket << std::endl;
#endif
} else {
// Nur unbekannte Fehler als Error loggen
std::cout << "[Error] Fehler beim Senden auf WebSocket " << socket << ": " << strerror(error) << std::endl;
}
}
} }
Json::Value Base::getJsonTree(const std::string& msg) { Json::Value Base::getJsonTree(const std::string& msg) {