You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
454 lines
9.4 KiB
454 lines
9.4 KiB
/*
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h> /* close() */
|
|
#include <stdlib.h>
|
|
#include <string.h> /* memset() */
|
|
#include <errno.h>
|
|
|
|
#include "UDPTCPNetwork.h"
|
|
|
|
TCP::~TCP() {
|
|
Close();
|
|
}
|
|
|
|
TCP::TCP() {
|
|
sock = 0;
|
|
writecnt = 0;
|
|
readcnt = 0;
|
|
islisten = 0;
|
|
};
|
|
|
|
TCP::TCP(int s) {
|
|
TCP();
|
|
sock = s;
|
|
// memset (&localaddr, 0x0, sizeof(localaddr));
|
|
// memset (&remoteaddr, 0x0, sizeof(remoteaddr));
|
|
writecnt = 0;
|
|
readcnt = 0;
|
|
islisten = 0;
|
|
};
|
|
|
|
TCP::TCP(string h, string p) {
|
|
TCP();
|
|
Connect (h,p);
|
|
};
|
|
|
|
|
|
int TCP::Listen(int port) {
|
|
char buffer[NET_BUFFERSIZE];
|
|
int err, i;
|
|
struct addrinfo hints, *res, *rp;
|
|
|
|
if (sock > 0) Close();
|
|
|
|
bzero (&hints, sizeof (struct addrinfo));
|
|
hints.ai_flags = AI_PASSIVE;
|
|
hints.ai_family = AF_INET6;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
if ((err = getaddrinfo (NULL, itoa(buffer, port, 32), &hints, &res)) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// walk through all results until we could connect
|
|
//
|
|
for (rp = res; rp != NULL; rp = rp->ai_next) {
|
|
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
|
if (sock == -1) continue;
|
|
|
|
i = 1;
|
|
if ((err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof (i))) != 0) {
|
|
printf ("%s:%d setsockopt error\n", __FILE__, __LINE__);
|
|
}
|
|
|
|
if ((err = bind (sock, rp->ai_addr, rp->ai_addrlen)) < 0) {
|
|
close (sock);
|
|
sock = -1;
|
|
continue;
|
|
}
|
|
if (listen (sock, 8) < 0) { // maximum of 8 connections at the time
|
|
close (sock);
|
|
sock = -1;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
freeaddrinfo (res);
|
|
|
|
if (rp == NULL) {
|
|
sock = -1;
|
|
return 0;
|
|
}
|
|
|
|
islisten = 1;
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
TCP* TCP::Accept() {
|
|
fd_set rfds;
|
|
struct timeval tv;
|
|
int retval, newsock, err, i;
|
|
struct sockaddr_storage cli_addr;
|
|
unsigned int cli_len = sizeof(cli_addr);
|
|
char host[NET_BUFFERSIZE];
|
|
char port[NET_BUFFERSIZE];
|
|
TCP *tcp = NULL;
|
|
|
|
if (sock <= 0) return NULL;
|
|
|
|
FD_ZERO(&rfds);
|
|
FD_SET(sock, &rfds);
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 1000;
|
|
|
|
retval = select (sock+1, &rfds, NULL, NULL, &tv);
|
|
if (retval == -1 && errno == EINTR) {
|
|
retval = 0;
|
|
}
|
|
else if (retval == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
else if (retval) {
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
|
newsock = accept (sock, (struct sockaddr *) &cli_addr, (int*) &cli_len);
|
|
#else
|
|
newsock = accept (sock, (struct sockaddr *) &cli_addr, &cli_len);
|
|
#endif
|
|
if (newsock < 0) return NULL;
|
|
tcp = new TCP();
|
|
tcp->SetSocket(newsock, &cli_addr, cli_len);
|
|
return tcp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int TCP::Connect(string h, string p) {
|
|
int i = 0;
|
|
|
|
// memset (&localaddr, 0x0, sizeof(localaddr));
|
|
// memset (&remoteaddr, 0x0, sizeof(remoteaddr));
|
|
// i = dns_filladdr(h, p, AF_INET, &remoteaddr);
|
|
// if (i == 0) return 0;
|
|
remote_host = h;
|
|
remote_port = p;
|
|
|
|
return Connect();
|
|
};
|
|
|
|
|
|
int TCP::Connect(string hostport, int defaultport) {
|
|
char buffer[32];
|
|
int pos = hostport.rfind(':', hostport.length());
|
|
if (pos == -1) {
|
|
remote_port = itoa (buffer, defaultport, 32);
|
|
remote_host = hostport;
|
|
}
|
|
else {
|
|
remote_port = hostport.substr (pos+1, hostport.length() - pos);
|
|
remote_host = hostport.substr (0, pos);
|
|
}
|
|
|
|
return Connect();
|
|
};
|
|
|
|
|
|
int TCP::Connect() {
|
|
int err, s;
|
|
struct addrinfo hints, *res, *rp;
|
|
struct timeval timeout;
|
|
|
|
memset(&hints, 0, sizeof(struct addrinfo));
|
|
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_flags = 0;
|
|
hints.ai_protocol = 0;
|
|
|
|
err = getaddrinfo(remote_host.c_str(), remote_port.c_str(), &hints, &res);
|
|
if (err != 0) {
|
|
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// walk through all results until we could connect
|
|
//
|
|
for (rp = res; rp != NULL; rp = rp->ai_next) {
|
|
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
|
|
|
// setup timeout to max 2 secs
|
|
timeout.tv_sec = 2;
|
|
timeout.tv_usec = 0;
|
|
setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
|
|
|
|
if (s == -1) continue;
|
|
if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1) {
|
|
sock = s;
|
|
break;
|
|
}
|
|
close(s);
|
|
}
|
|
|
|
freeaddrinfo(res);
|
|
|
|
//
|
|
// connect not successfull
|
|
//
|
|
if (rp == NULL) return 0;
|
|
|
|
writecnt = 0;
|
|
readcnt = 0;
|
|
|
|
return 1;
|
|
};
|
|
|
|
|
|
long int TCP::ReadPop (char *buffer, long int pktlen, long int bufferlen) {
|
|
memmove (buffer, buffer+pktlen, bufferlen-pktlen);
|
|
return bufferlen-pktlen;
|
|
}
|
|
|
|
|
|
long int TCP::Read(char *buffer, long int len) {
|
|
long int len_ = len;
|
|
|
|
if (sock <= 0) return -2;
|
|
len_ = read (sock, (void*)buffer, len);
|
|
// printf ("read: "); debug_mem(buffer, len_);
|
|
|
|
if (len_ < 0 && errno == EAGAIN) len_ = 0;
|
|
else if (len_ < 0 && errno != EAGAIN) {
|
|
// fprintf (stderr, "%s ERROR:%s\n", __FUNCTION__, strerror (errno));
|
|
len_ = -2;
|
|
}
|
|
else if (len_ == 0) len_ = -1;
|
|
if (len_ < 0) Close();
|
|
|
|
readcnt += len_;
|
|
|
|
return len_;
|
|
};
|
|
|
|
|
|
long int TCP::ReadTimeout(char *buffer, long int len, int timeout) {
|
|
int data = IsData (timeout);
|
|
|
|
if (data > 0) return Read (buffer, len);
|
|
else if (data < 0) return -1;
|
|
else return 0;
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//
|
|
// write data, generate no signal if some error occures
|
|
long int TCP::Write(char *buffer, long int len) {
|
|
int i;
|
|
int to = NET_MAX_RETRY;
|
|
|
|
if (sock <= 0) return -1;
|
|
|
|
do {
|
|
i = send (sock, buffer, len, MSG_NOSIGNAL);
|
|
} while (i == -1 && (to--) > 0 && errno == EINTR);
|
|
|
|
if (i < 0) Close ();
|
|
writecnt += i;
|
|
|
|
return i;
|
|
};
|
|
|
|
|
|
void TCP::Close() {
|
|
if (sock > 0) close (sock);
|
|
sock = -1;
|
|
islisten = false;
|
|
};
|
|
|
|
|
|
void TCP::SetSocket(int s, struct sockaddr_storage *saddr, int saddrlen) {
|
|
char host[NET_HOSTLEN];
|
|
char port[NET_PORTLEN];
|
|
int err;
|
|
|
|
|
|
if (sock > 0) Close();
|
|
if (s > 0) {
|
|
sock = s;
|
|
|
|
if (saddr != NULL) {
|
|
if ((err = getnameinfo ((struct sockaddr*) &saddr, saddrlen, host, NET_HOSTLEN,
|
|
port, NET_PORTLEN, NI_NUMERICHOST | NI_NUMERICSERV)) == 0) {
|
|
remote_host = host;
|
|
remote_port = port;
|
|
}
|
|
}
|
|
}
|
|
else sock = -1;
|
|
};
|
|
|
|
|
|
int TCP::IsConnected() {
|
|
return (sock > 0);
|
|
};
|
|
|
|
|
|
int TCP::IsData(int timeout) {
|
|
fd_set sockset;
|
|
struct timeval tval;
|
|
|
|
if (sock <= 0) return -1;
|
|
|
|
FD_ZERO (&sockset);
|
|
FD_SET (sock, &sockset);
|
|
tval.tv_sec = timeout / 1000;
|
|
tval.tv_usec = (timeout % 1000);
|
|
if ((select (sock + 1, &sockset, NULL, NULL, &tval)) != -1) {
|
|
if (FD_ISSET (sock, &sockset)) return 1;
|
|
return 0;
|
|
}
|
|
else {
|
|
if (errno == EBADF) sock = -1;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
|
|
int TCP::WebGetFile (string url, char *buffer, int maxsize) {
|
|
char outdata[NET_BUFFERSIZE];
|
|
char indata[NET_BUFFERSIZE];
|
|
char host[NET_HOSTLEN];
|
|
char port[NET_PORTLEN];
|
|
int breakup, len, head, i, buffpos = 0;
|
|
|
|
if (!IsConnected()) {
|
|
strncpy (host, WebGetURLHost (url).c_str(), NET_HOSTLEN);
|
|
strncpy (port, WebGetURLPort (url).c_str(), NET_PORTLEN);
|
|
Connect (host, port);
|
|
}
|
|
|
|
if (!IsConnected()) return -1;
|
|
|
|
// send http request
|
|
snprintf (outdata, NET_BUFFERSIZE, "GET %s HTTP/1.0\nUser-Agent: tcpclient \nHost: %s\n\n", WebGetURLFile (url).c_str(), host);
|
|
Write (outdata, strlen (outdata));
|
|
|
|
// wait for data start
|
|
i = breakup = 0;
|
|
head = 1;
|
|
while (!breakup && head && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) {
|
|
indata[len] = 0;
|
|
while (i < len -4 && head && !breakup) {
|
|
if (indata[i] == 0x0d && indata [i+1] == 0x0a && indata [i+2] == 0x0d && indata [i+3] == 0x0a) {
|
|
head = 0;
|
|
i = i + 4;
|
|
buffpos = len-i;
|
|
if (buffpos > maxsize) buffpos = maxsize;
|
|
memcpy (buffer, indata+i, buffpos);
|
|
}
|
|
|
|
else if (strncmp (indata+i, "Content-Length:", 15) == 0) {
|
|
i = i + 16;
|
|
}
|
|
|
|
else if (strncmp (indata+i, "403 ", 4) == 0) breakup = 1;
|
|
else i++;
|
|
}
|
|
}
|
|
|
|
// read data
|
|
while (!breakup && (len = ReadTimeout (indata, NET_BUFFERSIZE-1, 2000)) >= 0) {
|
|
i = len;
|
|
if (i > maxsize-buffpos) i = maxsize-buffpos;
|
|
if (i > 0) {
|
|
memcpy (buffer+buffpos, indata, i);
|
|
buffpos += i;
|
|
}
|
|
}
|
|
|
|
return buffpos;
|
|
};
|
|
|
|
const string TCP::WebGetURLHost (string url) {
|
|
string result;
|
|
int posSServPort = 7; // begin server:port
|
|
int posEServPort = 0; // end Server:Port
|
|
int posPort = -1; // port Position
|
|
|
|
posEServPort = url.find("/", 7);
|
|
result = url.substr (posSServPort, posEServPort-posSServPort);
|
|
posPort = result.find(":");
|
|
if (posPort > 0)
|
|
result = url.substr (posSServPort, posPort);
|
|
|
|
return result;
|
|
};
|
|
|
|
const string TCP::WebGetURLPort (string url) {
|
|
string result;
|
|
int posSServPort = 7; // begin server:port
|
|
int posEServPort = 0; // end Server:Port
|
|
int posPort = -1; // port Position
|
|
|
|
posEServPort = url.find("/", 7);
|
|
result = url.substr (posSServPort, posEServPort-posSServPort);
|
|
posPort = result.find(":");
|
|
if (posPort > 0)
|
|
result = result.substr (posPort+1);
|
|
else
|
|
result = "80";
|
|
|
|
return result;
|
|
};
|
|
|
|
const string TCP::WebGetURLFile (string url) {
|
|
string result;
|
|
int posEServPort = 0; // end Server:Port
|
|
|
|
posEServPort = url.find("/", 7);
|
|
result = url.substr (posEServPort);
|
|
|
|
return result;
|
|
};
|
|
|
|
|
|
const string TCP::GetRemoteAddr() {
|
|
string ret;
|
|
struct sockaddr addr;
|
|
socklen_t addrlen = sizeof (struct sockaddr);
|
|
char host[256] = "";
|
|
char port[256] = "";
|
|
|
|
if (getpeername (sock, &addr, &addrlen) == -1) {
|
|
printf ("getpeername error: %s\n", strerror(errno));
|
|
return ret;
|
|
}
|
|
|
|
if (getnameinfo (&addr, addrlen, host, 255, port, 255, 0) == -1) {
|
|
printf ("getnameinfo error: %s\n", strerror(errno));
|
|
return ret;
|
|
}
|
|
|
|
ret = (string)host + ":" + (string)port;
|
|
|
|
return ret;
|
|
};
|
|
|
|
|
|
const string TCP::GetLocalAddr() {
|
|
string ret;
|
|
|
|
|
|
|
|
return ret;
|
|
};
|
|
|
|
|