QTMSockets.cpp (TeXmacs-2.1.1-src) | : | QTMSockets.cpp (TeXmacs-2.1.2-src) | ||
---|---|---|---|---|
skipping to change at line 15 | skipping to change at line 15 | |||
* COPYRIGHT : (C) 2015 Denis RAUX | * COPYRIGHT : (C) 2015 Denis RAUX | |||
******************************************************************************* | ******************************************************************************* | |||
* This software falls under the GNU general public license version 3 or later. | * This software falls under the GNU general public license version 3 or later. | |||
* It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE | * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE | |||
* in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>. | * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>. | |||
******************************************************************************/ | ******************************************************************************/ | |||
#include "QTMSockets.hpp" | #include "QTMSockets.hpp" | |||
#include "scheme.hpp" | #include "scheme.hpp" | |||
#include "iterator.hpp" | #include "iterator.hpp" | |||
#include "analyze.hpp" | ||||
#ifndef OS_MINGW | #ifndef OS_MINGW | |||
#include <errno.h> | #include <errno.h> | |||
#include <unistd.h> | #include <unistd.h> | |||
#include <sys/types.h> | #include <sys/types.h> | |||
#include <sys/socket.h> | #include <sys/socket.h> | |||
#include <netinet/in.h> | #include <netinet/in.h> | |||
#include <netdb.h> | #include <netdb.h> | |||
#include <stdint.h> | #include <stdint.h> | |||
#include <fcntl.h> | #include <fcntl.h> | |||
#include <arpa/inet.h> | ||||
#define CONNECT ::connect | #define CONNECT ::connect | |||
#define CLOSE(a) close(a) | #define CLOSE(a) close(a) | |||
#define WRITE(a, b, c) ::write(a, b, c) | #define WRITE(a, b, c) ::write(a, b, c) | |||
#define ERRNO errno | #define ERRNO errno | |||
#define ERRSOC(a) a | #define ERRSOC(a) a | |||
#define GETADDRINFO getaddrinfo | #define GETADDRINFO getaddrinfo | |||
#define FREEADDRINFO freeaddrinfo | #define FREEADDRINFO freeaddrinfo | |||
#define ADDRINFO addrinfo | #define ADDRINFO addrinfo | |||
#define SOCKET socket | ||||
#define RECV recv | ||||
#define GAI_STRERROR gai_strerror | ||||
#define BIND bind | ||||
#define LISTEN listen | ||||
#define ACCEPT accept | ||||
#define INET_NTOP inet_ntop | ||||
#else | #else | |||
#define CONNECT wsoc::connect | #define CONNECT wsoc::connect | |||
#define CLOSE(a) wsoc::closesocket(a) | #define CLOSE(a) wsoc::closesocket(a) | |||
#define WRITE(a, b, c) wsoc::send(a, b, c, 0) | #define WRITE(a, b, c) wsoc::send(a, b, c, 0) | |||
#define ERRNO wsoc::WSAGetLastError() | #define ERRNO wsoc::WSAGetLastError() | |||
#define ERRSOC(a) WSA##a | #define ERRSOC(a) WSA##a | |||
#define GETADDRINFO wsoc::getaddrinfo | #define GETADDRINFO wsoc::getaddrinfo | |||
#define FREEADDRINFO wsoc::freeaddrinfo | #define FREEADDRINFO wsoc::freeaddrinfo | |||
#define ADDRINFO wsoc::addrinfo | #define ADDRINFO wsoc::addrinfo | |||
#define SOCKET wsoc::socket | ||||
#define RECV wsoc::recv | ||||
#define GAI_STRERROR wsoc::gai_strerror | ||||
#define BIND wsoc::bind | ||||
#define LISTEN wsoc::listen | ||||
#define ACCEPT wsoc::accept | ||||
#define INET_NTOP wsoc::inet_ntop | ||||
#endif | #endif | |||
unsigned dbg_cnt; | unsigned qtmsocket_debug_count; | |||
int socket_link::nr_ids= 0; | ||||
int socket_basic::count= 0; | int socket_basic::count= 0; | |||
#ifdef OS_MINGW | #ifdef OS_MINGW | |||
wsoc::WSADATA socket_basic::wsadata; | wsoc::WSADATA socket_basic::wsadata; | |||
#endif | #endif | |||
string | static string | |||
show_addr (unsigned long a) { | string_from_socket_address (SOCKADDR_STORAGE* sock) { | |||
string s(12); | static char tmp[128]; | |||
s << as_string (a & 0xff) << "."; a >>= 8; | if (sock->ss_family == AF_INET) { | |||
s << as_string (a & 0xff) << "."; a >>= 8; | #ifdef OS_MINGW | |||
s << as_string (a & 0xff) << "."; a >>= 8; | return wsoc::inet_ntoa (((SOCKADDR_IN*) sock)->sin_addr); | |||
s << as_string (a) ; | #else | |||
return s; | if (inet_ntop (AF_INET, &(((sockaddr_in*) sock)->sin_addr), | |||
tmp, sizeof(tmp)) == NULL) | ||||
return ""; | ||||
return tmp; | ||||
#endif | ||||
} | ||||
if (sock->ss_family == AF_INET6) { | ||||
#if !defined (OS_MINGW) || (_WIN32_WINNT >= 0x0600) | ||||
if (INET_NTOP (AF_INET6, &(((SOCKADDR_IN6*) sock)->sin6_addr), | ||||
tmp, sizeof(tmp)) == NULL) | ||||
return ""; | ||||
#else | ||||
return ""; | ||||
#endif | ||||
return tmp; | ||||
} | ||||
return ""; | ||||
} | } | |||
socket_basic::socket_basic (): st (ST_VOID) { | socket_basic::socket_basic (): st (ST_VOID) { | |||
#ifdef OS_MINGW | #ifdef OS_MINGW | |||
if (!count) { | if (!count) { | |||
using namespace wsoc; | using namespace wsoc; | |||
err=wsoc::WSAStartup (MAKEWORD (2,0), &wsadata); | err= WSAStartup (MAKEWORD (2,0), &wsadata); | |||
if (err) {st= ST_WSA; return;} | if (err) {st= ST_WSA; return;} | |||
} | } | |||
#endif | #endif | |||
count++; | count++; | |||
}; | }; | |||
socket_basic::~socket_basic () { | socket_basic::~socket_basic () { | |||
if (count > 0) --count; | if (count > 0) --count; | |||
#ifdef OS_MINGW | #ifdef OS_MINGW | |||
if (!count) wsoc::WSACleanup (); | if (!count) wsoc::WSACleanup (); | |||
#endif | #endif | |||
}; | }; | |||
socket_link::socket_link (int s, struct SOCKADDR_IN *addr): id (++nr_ids) { | socket_link::socket_link (int s, SOCKADDR_STORAGE* addr) { | |||
//cout << "Socket link [1] ~> " << id << LF; | id++; sock= s; qsnr= NULL; qsnw= NULL; | |||
sock= s; qsnr= NULL; qsnw= NULL; | ||||
if (st != ST_VOID) return; | if (st != ST_VOID) return; | |||
memcpy (&add, addr, sizeof(add)); | memcpy (&add, addr, sizeof(add)); | |||
qsnr= tm_new <QSocketNotifier> (s, QSocketNotifier::Read); | qsnr= tm_new<QSocketNotifier> (s, QSocketNotifier::Read); | |||
qsnw= tm_new <QSocketNotifier> (s, QSocketNotifier::Write); | qsnw= tm_new<QSocketNotifier> (s, QSocketNotifier::Write); | |||
if (!qsnr || !qsnw) { err= ERRNO; st= ST_NOTIF; return; } | ||||
if (!qsnr || !qsnw) { err=ERRNO; st=ST_NOTIF; return; } | ||||
QObject::connect (qsnr, SIGNAL(activated(int)), | QObject::connect (qsnr, SIGNAL(activated(int)), | |||
this, SLOT(data_set_ready(int))); | this, SLOT(data_set_ready(int))); | |||
QObject::connect (qsnw, SIGNAL(activated(int)), | QObject::connect (qsnw, SIGNAL(activated(int)), | |||
this, SLOT(ready_to_send(int))); | this, SLOT(ready_to_send(int))); | |||
DBG_IO ("Socket Created fd=" << sock); | DBG_IO ("Socket created with fd= " << sock); | |||
st= ST_OK; | st= ST_OK; | |||
} | } | |||
socket_link::socket_link(string host, u_short port): id (++nr_ids) { | socket_link::socket_link (string host, unsigned short port) { | |||
//cout << "Socket link [2] ~> " << id << LF; | ++id; qsnr= NULL; qsnw= NULL; | |||
qsnr= NULL; qsnw= NULL; | ||||
if (st != ST_VOID) return; | if (st != ST_VOID) return; | |||
/* this original code used the deprecated function gethostbyname | string host_tmp= host; | |||
this was signaled in the tracker (#34182, #46726) | if (starts (host, "[") && ends (host, "]")) | |||
Below the functionality is implemented using getaddrinfo, | host_tmp = host(1, N(host)-1); | |||
c_string _host (host_tmp); | ||||
//Create socket | ||||
sock= NMSPC (socket (AF_INET , SOCK_STREAM , 0)); | ||||
if (sock == -1) { err= errno; st= ST_SOCKET; return; } | ||||
// getting host | ||||
struct NMSPC (hostent) *hp= NMSPC (gethostbyname (as_charp (host))); | ||||
if (hp == NULL) { err= errno; st= ST_GETHOST; return; } | ||||
//Prepare the sockaddr_in structure | ||||
add.sin_family = AF_INET; | ||||
add.sin_addr.s_addr= *((unsigned long*)(hp->h_addr)); | ||||
add.sin_port = NMSPC(htons(port)); | ||||
if (CONNECT (sock, (struct SOCKADDR *) &add, sizeof (add))) { | ||||
err= errno; st= ST_CONNECTION; return; } | ||||
*/ | ||||
c_string _host (host); | ||||
c_string _port (as_string (port)); | c_string _port (as_string (port)); | |||
struct ADDRINFO hints; | struct ADDRINFO hints; | |||
struct ADDRINFO *result, *rp; | struct ADDRINFO *result, *rp; | |||
memset(&hints, 0, sizeof(hints)); | memset(&hints, 0, sizeof(hints)); | |||
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6, AF_INET for v4 only*/ | hints.ai_family = AF_UNSPEC; | |||
hints.ai_socktype = SOCK_STREAM; /* stream socket */ | hints.ai_socktype = SOCK_STREAM; | |||
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ | hints.ai_flags = AI_PASSIVE; | |||
hints.ai_protocol = 0; /* Any protocol */ | hints.ai_protocol = 0; | |||
hints.ai_canonname = NULL; | hints.ai_canonname = NULL; | |||
hints.ai_addr = NULL; | hints.ai_addr = NULL; | |||
hints.ai_next = NULL; | hints.ai_next = NULL; | |||
int x = GETADDRINFO (_host, _port, &hints, &result); | ||||
int x = GETADDRINFO(_host, _port, &hints, &result); | if (x != 0) { err= ERRNO; st= ST_GETHOST; return; }; | |||
if (x != 0) { err= ERRNO; st= ST_GETHOST; return; }; | ||||
for (rp = result; rp != NULL; rp = rp->ai_next) { | for (rp = result; rp != NULL; rp = rp->ai_next) { | |||
sock= NMSPC ( socket(rp->ai_family, rp->ai_socktype, | sock= SOCKET (rp->ai_family, rp->ai_socktype, | |||
rp->ai_protocol)); | rp->ai_protocol); | |||
if (sock == -1) | if (sock < 0) | |||
continue; | continue; | |||
if (CONNECT (sock, rp->ai_addr, rp->ai_addrlen) != -1) | ||||
if (CONNECT (sock, rp->ai_addr, rp->ai_addrlen) != -1) | break; | |||
break; /* Success */ | CLOSE (sock); | |||
CLOSE(sock); | ||||
} | ||||
if (rp == NULL) { /* No address succeeded */ | ||||
err= ERRNO; st= ST_CONNECTION; return; | ||||
} | } | |||
if (rp == NULL) { err= ERRNO; st= ST_CONNECTION; return; } | ||||
FREEADDRINFO(result); /* No longer needed */ | FREEADDRINFO (result); | |||
#ifndef OS_MINGW | ||||
#ifndef OS_MINGW | ||||
if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) { | if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) { | |||
err= errno; st= ST_FCNTL; return; } | err= errno; st= ST_FCNTL; return; } | |||
#else | #else | |||
{ | { | |||
unsigned long flags = -1; | using namespace wsoc; | |||
if (wsoc::ioctlsocket (sock, FIONBIO, &flags) == SOCKET_ERROR) { | u_long flags = -1; | |||
if (ioctlsocket (sock, FIONBIO, &flags) == SOCKET_ERROR) { | ||||
err= ERRNO; st= ST_FCNTL; return; } | err= ERRNO; st= ST_FCNTL; return; } | |||
} | } | |||
#endif | #endif | |||
qsnr= tm_new <QSocketNotifier> (sock, QSocketNotifier::Read); | qsnr= tm_new<QSocketNotifier> (sock, QSocketNotifier::Read); | |||
qsnw= tm_new <QSocketNotifier> (sock, QSocketNotifier::Write); | qsnw= tm_new<QSocketNotifier> (sock, QSocketNotifier::Write); | |||
if (!qsnr || !qsnw) { err= ERRNO; st= ST_NOTIF; return; } | if (!qsnr || !qsnw) { err= ERRNO; st= ST_NOTIF; return; } | |||
QObject::connect (qsnr, SIGNAL (activated(int)), | QObject::connect (qsnr, SIGNAL (activated(int)), | |||
this, SLOT (data_set_ready(int))); | this, SLOT (data_set_ready(int))); | |||
qsnw->setEnabled (false); | qsnw->setEnabled (false); | |||
QObject::connect (qsnw, SIGNAL (activated(int)), | QObject::connect (qsnw, SIGNAL (activated(int)), | |||
this, SLOT (ready_to_send(int))); | this, SLOT (ready_to_send(int))); | |||
DBG_IO ("Socket Created fd=" << sock); | DBG_IO ("Socket created with fd= " << sock); | |||
st= ST_OK; | st= ST_OK; | |||
} | } | |||
socket_link::~socket_link() { | socket_link::~socket_link() { | |||
DBG_IO ("Socket closing fd=" << sock); | DBG_IO ("Closing socket for fd= " << sock); | |||
if (qsnr) { qsnr->disconnect (SIGNAL(activated(int))); tm_delete (qsnr); } | if (qsnr) { qsnr->disconnect (SIGNAL(activated(int))); tm_delete (qsnr); } | |||
if (qsnw) { qsnw->disconnect (SIGNAL(activated(int))); tm_delete (qsnw); } | if (qsnw) { qsnw->disconnect (SIGNAL(activated(int))); tm_delete (qsnw); } | |||
if (sock != -1) { CLOSE (sock); sock=-1;} | if (sock != -1) { CLOSE (sock); sock=-1;} | |||
st= ST_CLOSED; | st= ST_CLOSED; | |||
} | } | |||
string | string | |||
socket_link::start () { | socket_link::start () { | |||
string ret; | string ret; | |||
switch(st) { | switch(st) { | |||
case ST_OK: return ""; break; | case ST_OK: return ""; break; | |||
case ST_VOID: ret= "Socket not Initialised"; break; | case ST_VOID: ret= "Socket not initialised"; break; | |||
case ST_SOCKET: ret= "Error in opening socket"; break; | case ST_SOCKET: ret= "Error in opening socket"; break; | |||
case ST_FCNTL: ret= "Error in setting blocking mode"; break; | case ST_FCNTL: ret= "Error in setting blocking mode"; break; | |||
case ST_BIND: ret= "Error during bind"; break; | case ST_BIND: ret= "Error during bind"; break; | |||
case ST_LISTEN: ret= "Error during listen"; break; | case ST_LISTEN: ret= "Error during listen"; break; | |||
case ST_CONNECTION: ret= "Error during connect"; break; | case ST_CONNECTION: ret= "Error during connect"; break; | |||
case ST_GETHOST: ret= "Error in getting host"; break; | case ST_GETHOST: ret= "Error in getting host"; break; | |||
case ST_NOTIF: ret= "Error in setting notifier"; break; | case ST_NOTIF: ret= "Error in setting notifier"; break; | |||
default: ret= "No error message"; | default: ret= "No error message"; | |||
} | } | |||
return ret * " errno:" * strerror(err); | return ret * " errno: " * strerror(err); | |||
} | } | |||
string& | string& | |||
socket_link::watch (int channel) { | socket_link::watch (int channel) { | |||
static string empty_string= ""; | static string empty_string= ""; | |||
if (channel == LINK_OUT) return inbuf; | if (channel == LINK_OUT) return inbuf; | |||
else return empty_string; | else return empty_string; | |||
} | } | |||
string | string | |||
socket_link::read (int channel) { | socket_link::read (int channel) { | |||
DBG_IO ("Socket read size=" << N(inbuf)); | DBG_IO ("Socket read size= " << N(inbuf)); | |||
if (channel == LINK_OUT && N(inbuf)) { | if (channel == LINK_OUT && N(inbuf)) { | |||
string r= inbuf; | string r= inbuf; | |||
inbuf= ""; | inbuf= ""; | |||
return r; | return r; | |||
} | } | |||
else return ""; | else return ""; | |||
} | } | |||
void | void | |||
socket_link::stop () { | socket_link::stop () { | |||
st= ST_HALTED; | st= ST_HALTED; | |||
emit disconnection(this); | emit disconnection (this); | |||
} | } | |||
void | void | |||
socket_link::data_set_ready (int s) { | socket_link::data_set_ready (int s) { | |||
char data[2048]; | char data[2048]; | |||
qsnr->setEnabled(false); | qsnr->setEnabled (false); | |||
int lgdata= RECV(s, data, sizeof(data), 0); | ||||
int lgdata = NMSPC (recv (s , data , sizeof(data) , 0)); | DBG_IO ("Socket incoming code= " << lgdata); | |||
DBG_IO ("Socket incoming code=" << lgdata); | if (lgdata == 0) { | |||
if (lgdata == 0) { | ||||
DBG_IO ("Client disconnected"); | DBG_IO ("Client disconnected"); | |||
stop (); | stop (); | |||
} | } | |||
else if (lgdata == -1) { | else if (lgdata == -1) { | |||
switch (ERRNO) { | switch (ERRNO) { | |||
case ERRSOC (EWOULDBLOCK): | case ERRSOC(EWOULDBLOCK): | |||
case ERRSOC (ECONNRESET): | case ERRSOC(ECONNRESET): | |||
case ERRSOC (ECONNABORTED): DBG_IO ("Client disconnected"); break; | case ERRSOC(ECONNABORTED): DBG_IO("Client disconnected"); break; | |||
default: DBG_IO ("Receiving error :" << ERRNO); | default: DBG_IO("Receiving error: " << ERRNO); | |||
} | } | |||
stop (); | stop (); | |||
} | } | |||
else { | else { | |||
inbuf << string (data, lgdata); | inbuf << string (data, lgdata); | |||
if (DEBUG_IO) { | if (DEBUG_IO) { | |||
string s (data, lgdata); | string s (data, lgdata); | |||
bool ok= true; | bool ok= true; | |||
for (int i=0; i<N(s); i++) | for (int i= 0; i < N(s); i++) | |||
if (((int) (unsigned char) s[i]) >= 128 || | if (((int) (unsigned char) s[i]) >= 128 || | |||
(((int) (unsigned char) s[i]) < 32 && | (((int) (unsigned char) s[i]) < 32 && | |||
s[i] != '\n' && s[i] != '\t')) ok= false; | s[i] != '\n' && s[i] != '\t')) ok= false; | |||
if (ok) { DBG_IO ("Data received:" << s); } | if (ok) { DBG_IO("Data received: " << s); } | |||
else { DBG_IO ("Binary data received size=" << N(s)); } | else { DBG_IO("Binary data received size= " << N(s)); } | |||
} | } | |||
qsnr->setEnabled (true); | qsnr->setEnabled (true); | |||
} | } | |||
} | } | |||
void | void | |||
socket_link::ready_to_send (int s) { | socket_link::ready_to_send (int s) { | |||
#ifdef OS_MINGW | #ifdef OS_MINGW | |||
using namespace wsoc; | using namespace wsoc; | |||
#endif | #endif | |||
qsnw->setEnabled (false); | qsnw->setEnabled (false); | |||
int sz= N (outbuf); | int sz= N(outbuf); | |||
if (sz) { | if (sz) { | |||
char *buf= as_charp (outbuf); | char* buf= as_charp (outbuf); | |||
int ret= WRITE (s, buf, sz); | int ret= WRITE(s, buf, sz); | |||
DBG_IO ("Socket outcoming code=" << ret); | DBG_IO ("Socket outcoming code= " << ret); | |||
if (ret >0) { | if (ret >0) { | |||
if (ret == sz) outbuf= ""; else outbuf= outbuf (ret,sz); | if (ret == sz) outbuf= ""; else outbuf= outbuf (ret, sz); | |||
sz -= ret; | sz -= ret; | |||
if (sz) qsnw->setEnabled (true); | if (sz) qsnw->setEnabled (true); | |||
} | } | |||
else if (ret <0) { | else if (ret <0) { | |||
DBG_IO ("Sending error:" << strerror(ERRNO)); | DBG_IO ("Sending error: " << strerror (ERRNO)); | |||
stop (); | stop (); | |||
} | } | |||
else qsnw->setEnabled (true); | else qsnw->setEnabled (true); | |||
} | } | |||
} | } | |||
void | void | |||
socket_link::listen (int msecs) { | socket_link::listen (int msecs) { | |||
#ifdef OS_MINGW | #ifdef OS_MINGW | |||
using namespace wsoc; | using namespace wsoc; | |||
#endif | #endif | |||
if (!alive ()) return; | if (!alive ()) return; | |||
ready_to_send (sock); // do some writing if any pending | ready_to_send (sock); | |||
fd_set rfds; | fd_set rfds; | |||
FD_ZERO (&rfds); | FD_ZERO (&rfds); | |||
FD_SET (sock, &rfds); | FD_SET (sock, &rfds); | |||
struct timeval tv; | struct timeval tv; | |||
tv.tv_sec = msecs / 1000; | tv.tv_sec = msecs / 1000; | |||
tv.tv_usec = 1000 * (msecs % 1000); | tv.tv_usec= 1000 * (msecs % 1000); | |||
int nr= select (sock+1, &rfds, NULL, NULL, &tv); | int nr= select (sock+1, &rfds, NULL, NULL, &tv); | |||
if (nr ==1) data_set_ready (sock); //collect data | if (nr == 1) data_set_ready (sock); | |||
DBG_IO ("listen result :" << nr); | DBG_IO ("Listenning result: " << nr); | |||
if (nr == -1) stop(); | if (nr == -1) stop(); | |||
} | } | |||
void | void | |||
socket_link::write (string s, int channel) { | socket_link::write (string s, int channel) { | |||
DBG_IO ("Socket write size=" << N(s)); | DBG_IO ("Socket write size= " << N(s)); | |||
if ((!alive ()) || (channel != LINK_IN) || !N(s)) return; | if ((!alive ()) || (channel != LINK_IN) || !N(s)) return; | |||
outbuf << s; | outbuf << s; | |||
qsnw->setEnabled(true); | qsnw->setEnabled(true); | |||
} | } | |||
socket_server::socket_server (in_addr_t add, u_short port) { | socket_server::socket_server (string host, unsigned short port) { | |||
struct SOCKADDR_IN server; | c_string _port (as_string (port)); | |||
c_string _host (host); | ||||
//Create socket | struct ADDRINFO hints; | |||
sock= NMSPC (socket (AF_INET , SOCK_STREAM , 0)); | struct ADDRINFO *result, *rp; | |||
if (sock == -1) { err= ERRNO; st= ST_SOCKET; return;} | memset(&hints, 0, sizeof(struct ADDRINFO)); | |||
hints.ai_family = AF_UNSPEC; | ||||
hints.ai_socktype = SOCK_STREAM; | ||||
hints.ai_flags = AI_PASSIVE; | ||||
hints.ai_protocol = 0; | ||||
hints.ai_canonname = NULL; | ||||
hints.ai_addr = NULL; | ||||
hints.ai_next = NULL; | ||||
int x = GETADDRINFO (host == "" ? (char*) NULL : (char*)_host, | ||||
_port, &hints, &result); | ||||
if (x != 0) { | ||||
DBG_IO(GAI_STRERROR(x)); | ||||
err= ERRNO; | ||||
st= ST_GETHOST; | ||||
return; | ||||
} | ||||
sock = -1; | ||||
for (rp = result; rp != NULL; rp = rp->ai_next) { | ||||
DBG_IO ("Serving at " * | ||||
string_from_socket_address ((SOCKADDR_STORAGE*) rp->ai_addr)); | ||||
sock= SOCKET (rp->ai_family, rp->ai_socktype, rp->ai_protocol); | ||||
if (sock < 0) | ||||
continue; | ||||
#ifndef OS_MINGW | #ifndef OS_MINGW | |||
if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) { | if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) | |||
err= ERRNO; st= ST_FCNTL; return; } | continue; | |||
#else | #else | |||
{ | { using namespace wsoc; | |||
unsigned long flags = -1; | u_long flags = -1; | |||
if (wsoc::ioctlsocket (sock, FIONBIO, &flags) == SOCKET_ERROR) { | if (ioctlsocket (sock, FIONBIO, &flags) == SOCKET_ERROR) | |||
err= ERRNO; st= ST_FCNTL; return; } | continue; | |||
} | } | |||
#endif | #endif | |||
if (BIND (sock, rp->ai_addr, rp->ai_addrlen) == 0) | ||||
//Prepare the sockaddr_in structure | break; | |||
server.sin_family= AF_INET; | DBG_IO (strerror (errno)); | |||
server.sin_addr.s_addr= add; | DBG_IO ("Socket bind failed"); | |||
server.sin_port= NMSPC(htons(port)); | CLOSE (sock); | |||
sock = -1; | ||||
if (NMSPC (bind (sock, (struct SOCKADDR *)&server, sizeof(server)))) { | } | |||
err=ERRNO; st=ST_BIND; return; } | FREEADDRINFO (result); | |||
if (NMSPC(listen (sock , 3))) { err= ERRNO; st= ST_LISTEN; return; } | if (sock == -1) { | |||
qsnc= new QSocketNotifier (sock, QSocketNotifier::Read); | DBG_IO ("Cannot find socket binding for server"); | |||
err= ERRNO; | ||||
QObject::connect(qsnc, SIGNAL(activated(int)), this, SLOT(connection(int))); | st= ST_BIND; | |||
DBG_IO ("wait for connection"); | return; | |||
} | ||||
if (LISTEN (sock, 10) != 0) { | ||||
DBG_IO ("Cannot listen on server socket"); | ||||
err= ERRNO; | ||||
st= ST_LISTEN; | ||||
return; | ||||
} | ||||
qsnc= tm_new<QSocketNotifier> (sock, QSocketNotifier::Read); | ||||
QObject::connect (qsnc, SIGNAL (activated(int)), this, SLOT (connection(int))) | ||||
; | ||||
DBG_IO ("Wait for connection"); | ||||
} | } | |||
void | void | |||
socket_server::connection (int s) { | socket_server::connection (int s) { | |||
int sclt; socket_link *clt; | int sclt; socket_link* clt; | |||
struct SOCKADDR_IN cltadd; | SOCKADDR_STORAGE cltadd; | |||
socklen_t sz= sizeof (cltadd); | socklen_t sz= sizeof (cltadd); | |||
if (!qsnc->isEnabled ()) return; | if (!qsnc->isEnabled ()) return; | |||
//accept connection from an incoming client | sclt= ACCEPT (s, (SOCKADDR*) &cltadd, &sz); | |||
sclt= NMSPC (accept (s, (SOCKADDR*) &cltadd, &sz)); | ||||
if (sclt > 0) { | if (sclt > 0) { | |||
clt= tm_new <socket_link> (sclt, &cltadd); | clt= tm_new<socket_link> (sclt, &cltadd); | |||
if (clt) { | if (clt) { | |||
if (clt->alive ()) { | if (clt->alive ()) { | |||
connect (clt, SIGNAL (disconnection(socket_link*)), this, | connect (clt, SIGNAL (disconnection(socket_link*)), this, | |||
SLOT (disconnection (socket_link*))); | SLOT (disconnection (socket_link*))); | |||
clts->insert ((pointer) clt); | clts->insert ((pointer) clt); | |||
call ("server-add", object (clt->getid ())); | call ("server-add", object (clt->getid ())); | |||
DBG_IO ("Client Connected " << show_addr (cltadd.sin_addr.s_addr) | DBG_IO ("Client Connected from " | |||
<< " id:" << clt->getid ()); | << string_from_socket_address (&cltadd) | |||
<< ", with id: " << clt->getid ()); | ||||
} | } | |||
else tm_delete (clt); | else tm_delete (clt); | |||
} | } | |||
} | } | |||
else switch (ERRNO) { | else switch (ERRNO) { | |||
case ERRSOC (EWOULDBLOCK): | case ERRSOC (EWOULDBLOCK): | |||
case ERRSOC (ECONNABORTED): break; | case ERRSOC (ECONNABORTED): break; | |||
default: err=ERRNO; qsnc->setEnabled (false); st=ST_CONNECTION; | default: err= ERRNO; qsnc->setEnabled (false); st= ST_CONNECTION; | |||
} | } | |||
} | } | |||
void | void | |||
socket_server::disconnection(socket_link* clt) { | socket_server::disconnection (class socket_link* clt) { | |||
call ("server-remove", object (clt->getid())); | call ("server-remove", object (clt->getid())); | |||
clts->remove((pointer) clt); | clts->remove ((pointer) clt); | |||
tm_delete(clt); | tm_delete (clt); | |||
} | } | |||
string | string | |||
socket_server::read (IdClt id) { | socket_server::read (int id) { | |||
class socket_link *clt= find_client (id); | socket_link *clt= find_client (id); | |||
if (!clt) return ""; | if (!clt) return ""; | |||
bool success; | bool success; | |||
string back= clt->read_packet (LINK_OUT, 0, success); | string back= clt->read_packet (LINK_OUT, 0, success); | |||
return back; | return back; | |||
} | } | |||
void | void | |||
socket_server::write (IdClt id, string s) { | socket_server::write (int id, string s) { | |||
class socket_link *clt= find_client (id); | socket_link *clt= find_client (id); | |||
if (clt) clt->write_packet(s, LINK_IN); | if (clt) clt->write_packet(s, LINK_IN); | |||
} | } | |||
class socket_link * | socket_link * | |||
socket_server::find_client(IdClt id) { | socket_server::find_client (int id) { | |||
iterator<pointer> it= iterate (clts); | iterator<pointer> it= iterate (clts); | |||
while (it->busy ()) { | while (it->busy ()) { | |||
socket_link* clt= (socket_link*) it->next (); | socket_link* clt= (socket_link*) it->next (); | |||
if (clt->getid() == id) return clt; | if (clt->getid() == id) return clt; | |||
} | } | |||
array<IdClt> ids; | array<int> ids; | |||
it= iterate (clts); | it= iterate (clts); | |||
while (it->busy ()) { | while (it->busy ()) { | |||
socket_link* clt= (socket_link*) it->next (); | socket_link* clt= (socket_link*) it->next (); | |||
ids << clt->getid(); | ids << clt->getid(); | |||
} | } | |||
DBG_IO ("Client not found, Id = " << id << ", Among = " << ids); | DBG_IO ("Client not found, id= " << id << ", among= " << ids); | |||
return NULL; | return NULL; | |||
} | } | |||
socket_server::~socket_server() { | socket_server::~socket_server () { | |||
iterator<pointer> it= iterate (clts); | iterator<pointer> it= iterate (clts); | |||
while (it->busy ()) { | while (it->busy ()) { | |||
socket_link* clt= (socket_link*) it->next (); | socket_link* clt= (socket_link*) it->next (); | |||
disconnection (clt); | disconnection (clt); | |||
} | } | |||
} | } | |||
string | string | |||
debug_io_string (string s) { | debug_io_string (string s) { | |||
int i, n= N(s); | int i, n= N(s); | |||
End of changes. 56 change blocks. | ||||
152 lines changed or deleted | 190 lines changed or added |