diff sources/network.cpp @ 0:bafff9de2a76

Initial commit since summer'07
author Vlad Glagolev <enqlave@gmail.com>
date Sun, 20 Jan 2008 19:25:25 +0300
parents
children 19227b0b7cc1
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sources/network.cpp	Sun Jan 20 19:25:25 2008 +0300
@@ -0,0 +1,297 @@
+/**
+ * network.cpp (2007-04-02)
+ *
+ * -- CABAL -- network essentials (sockets, etc.)
+ *
+ * Copyright (c) 2007 Vlad Glagolev <enqlave@gmail.com>
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "cabal.h"	// required: network.h
+
+Network::Network()
+{
+	cout << "NETWORK: going online...\n";
+}
+
+Network::~Network()
+{
+	socketClose();
+
+	cout << "NETWORK: offline\n";
+}
+
+void Network::msgSend (string data)
+{
+	if (cs == -1)
+		return;
+
+	if (CABAL->debug)
+		cout << "<- " << cs << " -- " << data << endl;
+
+	send (cs, (data + "\n").c_str(), (data + "\n").size(), 0);
+}
+
+string Network::msgReceive()
+{
+	if (cs == -1)
+		return 0;
+
+	if (canRead(cs) == 1) {
+		string sbuffer = "";
+		char cbuffer;
+
+		int err = recv (cs, &cbuffer, 1, 0);
+
+		if (err > 0) {
+			sbuffer += cbuffer;
+
+			while (1) {
+				if (sbuffer[sbuffer.size() - 1] == '\n') {
+					sbuffer = (sbuffer.substr (0, 1) == ":")
+						? sbuffer.substr (1, sbuffer.size() - 3)
+						: sbuffer.substr (0, sbuffer.size() - 2);
+
+					if (CABAL->debug)
+						cout << "-> " << cs << " -- " << sbuffer << endl;
+
+					return sbuffer;
+				}
+
+				err = recv (cs, &cbuffer, 1, 0);
+
+				if (err == 0)
+					shut ("remote server closed connection");
+				else if (err < 0)
+					shut ("failed to receive data");
+				else
+					sbuffer += cbuffer;
+			}
+		} else if (err == 0)
+			shut ("remote server closed connection");
+
+		return sbuffer;
+	}
+
+	return "";
+}
+
+bool Network::hostResolve(pchar name, struct address_type *a, int inet)
+{
+#ifdef ENABLE_IPV6
+
+	bool e = 0;
+
+	struct addrinfo hints, *res, *reso;
+	struct sockaddr_in *in;
+	struct sockaddr_in6 *in6;
+
+	memset(&hints, 0, sizeof (hints));
+
+	hints.ai_socktype = SOCK_STREAM;
+
+	if (getaddrinfo(name, "domain", &hints, &res) < 0)
+		return 0;
+
+	reso = res;
+
+	while (res != 0) {
+		if (!inet || res->ai_family == inet) {
+			switch (res->ai_family) {
+				case AF_INET6:
+					a->inet = AF_INET6;
+					in6 = (struct sockaddr_in6 *)res->ai_addr;
+					memcpy (&a->sa6.sin6_addr, &in6->sin6_addr, \
+						sizeof (struct in6_addr));
+					e = 1;
+				break;
+				case AF_INET:
+					a->inet = AF_INET;
+					in = (struct sockaddr_in *)res->ai_addr;
+					memcpy (&a->sa.sin_addr, &in->sin_addr, \
+						sizeof (struct in_addr));
+					e = 1;
+				break;
+				default:
+					e = 0;
+			}
+		}
+
+		if (e)
+			break;
+
+		res = res->ai_next;
+	}
+
+	freeaddrinfo (reso);
+
+	return e;
+
+#else
+
+	if (inet != 0 && inet != AF_INET)
+		return 0;
+
+	a->inet = AF_INET;
+
+	struct hostent *he;
+
+	if ((he = gethostbyname (name)) == 0) {
+		a->sa.sin_addr.s_addr = inet_addr (name);
+
+		if (a->sa.sin_addr.s_addr == 1)
+			return 0;
+	} else
+		memcpy (&a->sa.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
+
+	return 1;
+
+#endif  // ENABLE_IPV6
+}
+
+bool Network::tcpActivate (int port, pchar host)
+{
+	cs = socket (address.inet, SOCK_STREAM, IPPROTO_TCP);
+
+	if (cs == -1)
+		return 0;
+
+	if (host != 0) {
+		struct address_type a;
+
+		if (!hostResolve (host, &a, address.inet)) {
+			close (cs);
+			return 0;
+		}
+
+		int e;
+
+#ifdef ENABLE_IPV6
+		if (a.inet == AF_INET6)
+			e = bind (cs, (struct sockaddr *)&a.sa6, sizeof (a.sa6));
+		else
+#endif // ENABLE_IPV6
+			e = bind (cs, (struct sockaddr *)&a.sa, sizeof (a.sa));
+
+		if (e == -1) {
+			close (cs);
+			return 0;
+		}
+	}
+
+#ifdef ENABLE_IPV6
+	if (address.inet == AF_INET6) {
+		address.sa6.sin6_family = AF_INET6;
+		address.sa6.sin6_port = htons (port);
+	}
+	else {
+#endif // ENABLE_IPV6
+		address.sa.sin_family = AF_INET;
+		address.sa.sin_port = htons (port);
+#ifdef ENABLE_IPV6
+	}
+#endif // ENABLE_IPV6
+
+	socklen_t parm;
+
+	setsockopt (cs, IPPROTO_TCP, TCP_NODELAY, (pchar)&parm, sizeof (parm));
+
+	connected = 0;
+	connecting = 1;
+
+	cout << "NETWORK: socket opened........... " << cs << endl;
+
+	return 1;
+}
+
+bool Network::hostOpen()
+{
+	int e;
+
+#ifdef ENABLE_IPV6
+	if (address.inet == AF_INET6)
+		e = connect (cs, (struct sockaddr *)&address.sa6, sizeof (address.sa6));
+	else
+#endif // ENABLE_IPV6
+		e = connect (cs, (struct sockaddr *)&address.sa, sizeof (address.sa));
+
+	if (e == -1) {
+		if (errno == EISCONN) {
+			connected = 1;
+			connecting = 0;
+
+			return 1;
+		}
+
+		if (errno != EWOULDBLOCK && errno != EINPROGRESS && errno != EALREADY) {
+			socketClose();
+
+			connecting = 0;
+
+			return 0;
+		}
+
+		return 1;
+	}
+
+	connected = 1;
+	connecting = 0;
+
+	cout << "NETWORK: socket connected........ " << cs << endl;
+
+	return 1;
+}
+
+bool Network::socketClose()
+{
+	if (cs == -1)
+		return 0;
+
+	close (cs);
+
+	cs = -1;
+
+	return 1;
+}
+
+int Network::canRead (int socket)
+{
+	FD_ZERO (&rs);
+	FD_SET (socket, &rs);
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 1;
+
+	int e = select (socket + 1, &rs, 0, 0, &timeout);
+
+	FD_ZERO (&rs);
+
+	return e;
+}
+
+int Network::canWrite (int socket)
+{
+	FD_ZERO (&ws);
+	FD_SET (socket, &ws);
+
+	timeout.tv_sec = 0;
+	timeout.tv_usec = 1;
+
+	int e = select (socket + 1, 0, &ws, 0, &timeout);
+
+	FD_ZERO (&ws);
+
+	return e;
+}