summaryrefslogtreecommitdiff
path: root/bouncer/socketcommon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'bouncer/socketcommon.cpp')
-rw-r--r--bouncer/socketcommon.cpp174
1 files changed, 174 insertions, 0 deletions
diff --git a/bouncer/socketcommon.cpp b/bouncer/socketcommon.cpp
new file mode 100644
index 0000000..7bc55b6
--- /dev/null
+++ b/bouncer/socketcommon.cpp
@@ -0,0 +1,174 @@
+#include "core.h"
+
+/*static*/ bool SocketRWCommon::setSocketNonBlocking(int sock) {
+ int opts = fcntl(sock, F_GETFL);
+ if (opts < 0) {
+ perror("Could not get fcntl options\n");
+ return false;
+ }
+ opts |= O_NONBLOCK;
+ if (fcntl(sock, F_SETFL, opts) == -1) {
+ perror("Could not set fcntl options\n");
+ return false;
+ }
+ return true;
+}
+
+
+SocketRWCommon::SocketRWCommon(NetCore *_netCore) {
+ netCore = _netCore;
+ sock = -1;
+ state = CS_DISCONNECTED;
+#ifdef USE_GNUTLS
+ tlsActive = false;
+#endif
+}
+SocketRWCommon::~SocketRWCommon() {
+ close();
+}
+
+#ifdef USE_GNUTLS
+bool SocketRWCommon::hasTlsPendingData() const {
+ if (tlsActive)
+ return (gnutls_record_check_pending(tls) > 0);
+ else
+ return false;
+}
+
+bool SocketRWCommon::tryTLSHandshake() {
+ int hsRet = gnutls_handshake(tls);
+ if (gnutls_error_is_fatal(hsRet)) {
+ printf("[SocketRWCommon::tryTLSHandshake] gnutls_handshake borked\n");
+ gnutls_perror(hsRet);
+ close();
+ return false;
+ }
+
+ if (hsRet == GNUTLS_E_SUCCESS) {
+ // We're in !!
+ state = CS_CONNECTED;
+
+ inputBuf.clear();
+ outputBuf.clear();
+
+ printf("[SocketRWCommon connected via SSL!]\n");
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+void SocketRWCommon::close() {
+ if (sock != -1) {
+#ifdef USE_GNUTLS
+ if (tlsActive)
+ gnutls_bye(tls, GNUTLS_SHUT_RDWR);
+#endif
+ shutdown(sock, SHUT_RDWR);
+ ::close(sock);
+ }
+
+ sock = -1;
+ inputBuf.clear();
+ outputBuf.clear();
+ state = CS_DISCONNECTED;
+
+#ifdef USE_GNUTLS
+ if (tlsActive) {
+ gnutls_deinit(tls);
+ tlsActive = false;
+ }
+#endif
+}
+
+void SocketRWCommon::readAction() {
+ // Ensure we have at least 0x200 bytes space free
+ // (Up this, maybe?)
+ int bufSize = inputBuf.size();
+ int requiredSize = bufSize + 0x200;
+ if (requiredSize > inputBuf.capacity())
+ inputBuf.setCapacity(requiredSize);
+
+ ssize_t amount;
+
+#ifdef USE_GNUTLS
+ if (tlsActive) {
+ amount = gnutls_record_recv(tls,
+ &inputBuf.data()[bufSize],
+ 0x200);
+ } else
+#endif
+ {
+ amount = recv(sock,
+ &inputBuf.data()[bufSize],
+ 0x200,
+ 0);
+ }
+
+
+ if (amount > 0) {
+ // Yep, we have data
+ printf("[fd=%d] Read %d bytes\n", sock, amount);
+ inputBuf.resize(bufSize + amount);
+
+ processReadBuffer();
+
+ } else if (amount == 0) {
+ printf("[fd=%d] Read 0! Socket closing.\n", sock);
+ close();
+
+ } else if (amount < 0) {
+#ifdef USE_GNUTLS
+ if (tlsActive) {
+ if (gnutls_error_is_fatal(amount)) {
+ printf("Error while reading [gnutls %d]!\n", amount);
+ close();
+ }
+ } else
+#endif
+ {
+ perror("Error while reading!");
+ close();
+ }
+ }
+}
+
+void SocketRWCommon::writeAction() {
+ // What can we get rid of...?
+ ssize_t amount;
+
+#ifdef USE_GNUTLS
+ if (tlsActive) {
+ amount = gnutls_record_send(tls,
+ outputBuf.data(),
+ outputBuf.size());
+ } else
+#endif
+ {
+ amount = send(sock,
+ outputBuf.data(),
+ outputBuf.size(),
+ 0);
+ }
+
+ if (amount > 0) {
+ printf("[fd=%d] Wrote %d bytes out of %d\n", sock, amount, outputBuf.size());
+ outputBuf.trimFromStart(amount);
+ } else if (amount == 0)
+ printf("Sent 0!\n");
+ else if (amount < 0) {
+#ifdef USE_GNUTLS
+ if (tlsActive) {
+ if (gnutls_error_is_fatal(amount)) {
+ printf("Error while sending [gnutls %d]!\n", amount);
+ close();
+ }
+ } else
+#endif
+ {
+ perror("Error while sending!");
+ close();
+ }
+ }
+}