Mercurial > cabal
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; +}
