1
2
3 #include "ttcpip.h"
4 #include "tconvert.h"
5
6 #ifdef _WIN32
7 #include <winsock2.h>
8 #else
9 #include <errno.h> /* obligatory includes */
10 #include <signal.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/wait.h>
16 #include <netinet/in.h>
17 #include <netdb.h>
18 #endif
19
20 #include "tthreadmessage.h"
21 #include "tthread.h"
22 #ifndef _WIN32
23 #define SOCKET_ERROR -1
24 #endif
25
26 #include <string>
27 using namespace std;
28
29 #define MAXHOSTNAME 1024
30
31 int establish(unsigned short portnum, int &sock);
32 int get_connection(int s);
33 void fireman(int);
34 void do_something(int);
35
36 bool Sthutdown = false;
37
38 //#define TRACE
39
40 //---------------------------------------------------------------------
41
42 class TTcpIpServerImp {
43 public:
TTcpIpServerImp(int port)44 TTcpIpServerImp(int port) : m_port(port), m_s(-1), m_server(0) {}
45
46 int readData(int sock, QString &data);
47 void onReceive(int sock, const QString &data);
48
49 int m_s; // socket id
50 int m_port;
51 TTcpIpServer *m_server; // back pointer
52
53 TThread::Mutex m_mutex;
54 };
55
56 //---------------------------------------------------------------------
57
readData(int sock,QString & data)58 int TTcpIpServerImp::readData(int sock, QString &data) {
59 int cnt = 0;
60 char buff[1025];
61 memset(buff, 0, sizeof(buff));
62
63 #ifdef _WIN32
64 if ((cnt = recv(sock, buff, sizeof(buff) - 1, 0)) < 0) {
65 int err = WSAGetLastError();
66 // GESTIRE L'ERRORE SPECIFICO
67 return -1;
68 }
69 #else
70 if ((cnt = read(sock, buff, sizeof(buff) - 1)) < 0) {
71 printf("socket read failure %d\n", errno);
72 perror("network server");
73 close(sock);
74 return -1;
75 }
76 #endif
77
78 if (cnt == 0) return 0;
79
80 #ifdef TRACE
81 cout << buff << endl << endl;
82 #endif
83
84 string aa(buff);
85 int x1 = aa.find("#$#THS01.00");
86 x1 += sizeof("#$#THS01.00") - 1;
87 int x2 = aa.find("#$#THE");
88
89 string ssize;
90 for (int i = x1; i < x2; ++i) ssize.push_back(buff[i]);
91
92 int dataSize = std::stoi(ssize);
93
94 unsigned long size = dataSize;
95 data = QString(buff + x2 + sizeof("#$#THE") - 1);
96 size -= data.size();
97
98 while (size > 0) {
99 memset(buff, 0, sizeof(buff));
100
101 #ifdef _WIN32
102 if ((cnt = recv(sock, buff, sizeof(buff) - 1, 0)) < 0) {
103 int err = WSAGetLastError();
104 // GESTIRE L'ERRORE SPECIFICO
105 return -1;
106 }
107 #else
108 if ((cnt = read(sock, buff, sizeof(buff) - 1)) < 0) {
109 printf("socket read failure %d\n", errno);
110 perror("network server");
111 close(sock);
112 return -1;
113 }
114 #endif
115 else if (cnt == 0) {
116 break; // break out of loop
117 } else if (cnt < (int)sizeof(buff)) {
118 buff[cnt] = '\0';
119 data += QString(buff);
120 // break; // break out of loop
121 } else {
122 data += QString(buff);
123 }
124
125 #ifdef TRACE
126 cout << buff << endl << endl;
127 #endif
128
129 size -= cnt;
130 }
131
132 #ifdef TRACE
133 cout << "read " << toString((int)data.length()) << " on " << dataSize << endl
134 << endl;
135 #endif
136
137 if (data.size() < dataSize) return -1;
138
139 #ifdef TRACE
140 cout << data.toStdString() << endl;
141 #endif
142
143 return 0;
144 }
145
146 #if 0
147
148 int TTcpIpServerImp::readData(int sock, string &data)
149 {
150 int cnt = 0;
151 char buff[1024];
152
153 do
154 {
155 memset (buff,0,sizeof(buff));
156
157 #ifdef _WIN32
158 if (( cnt = recv(sock, buff, sizeof(buff), 0)) < 0 )
159 {
160 int err = WSAGetLastError();
161 // GESTIRE L'ERRORE SPECIFICO
162 return -1;
163 }
164 #else
165 if (( cnt = read (sock, buff, sizeof(buff))) < 0 )
166 {
167 printf("socket read failure %d\n", errno);
168 perror("network server");
169 close(sock);
170 return -1;
171 }
172 #endif
173 else
174 if (cnt == 0)
175 break; // break out of loop
176
177 data += string(buff);
178 }
179 while (cnt != 0); // do loop condition
180
181 return 0;
182 }
183
184 #endif
185
186 //#define PRIMA
187
188 #ifdef PRIMA
189
readData(int sock,string & data)190 int TTcpIpServerImp::readData(int sock, string &data) {
191 int cnt = 0;
192 char buff[1024];
193
194 do {
195 memset(buff, 0, sizeof(buff));
196
197 #ifdef _WIN32
198 if ((cnt = recv(sock, buff, sizeof(buff), 0)) < 0) {
199 int err = WSAGetLastError();
200 // GESTIRE L'ERRORE SPECIFICO
201 return -1;
202 }
203 #else
204 if ((cnt = read(sock, buff, sizeof(buff))) < 0) {
205 printf("socket read failure %d\n", errno);
206 perror("network server");
207 close(sock);
208 return -1;
209 }
210 #endif
211 else if (cnt == 0) {
212 break; // break out of loop
213 } else if (cnt < sizeof(buff)) {
214 data += string(buff);
215 // break; // break out of loop
216 } else {
217 data += string(buff);
218 }
219 } while (cnt != 0); // do loop condition
220
221 return 0;
222 }
223
224 #endif
225
226 //---------------------------------------------------------------------
227
onReceive(int sock,const QString & data)228 void TTcpIpServerImp::onReceive(int sock, const QString &data) {
229 QMutexLocker sl(&m_mutex);
230 m_server->onReceive(sock, data);
231 }
232
233 //---------------------------------------------------------------------
234
TTcpIpServer(int port)235 TTcpIpServer::TTcpIpServer(int port) : m_imp(new TTcpIpServerImp(port)) {
236 m_imp->m_server = this;
237
238 #ifdef _WIN32
239 // Windows Socket startup
240 WSADATA wsaData;
241 WORD wVersionRequested = MAKEWORD(1, 1);
242 int irc = WSAStartup(wVersionRequested, &wsaData);
243 if (irc != 0) throw("Windows Socket Startup failed");
244 #endif
245 }
246
247 //---------------------------------------------------------------------
248
~TTcpIpServer()249 TTcpIpServer::~TTcpIpServer() {
250 if (m_imp->m_s != -1)
251 #ifdef _WIN32
252 closesocket(m_imp->m_s);
253 WSACleanup();
254 #else
255 std::cout << "closing socket" << std::endl;
256 close(m_imp->m_s);
257 #endif
258 }
259
260 //---------------------------------------------------------------------
261
getPort() const262 int TTcpIpServer::getPort() const { return m_imp->m_port; }
263
264 //---------------------------------------------------------------------
265
shutdown_cb(int)266 static void shutdown_cb(int) { Sthutdown = true; }
267
268 //---------------------------------------------------------------------
269
270 class DataReader final : public TThread::Runnable {
271 public:
DataReader(int clientSocket,std::shared_ptr<TTcpIpServerImp> serverImp)272 DataReader(int clientSocket, std::shared_ptr<TTcpIpServerImp> serverImp)
273 : m_clientSocket(clientSocket), m_serverImp(std::move(serverImp)) {}
274
275 void run() override;
276
277 int m_clientSocket;
278 std::shared_ptr<TTcpIpServerImp> m_serverImp;
279 };
280
run()281 void DataReader::run() {
282 QString data;
283 int ret = m_serverImp->readData(m_clientSocket, data);
284 if (ret != -1) {
285 if (data == QString("shutdown"))
286 Sthutdown = true;
287 else
288 m_serverImp->onReceive(m_clientSocket, data);
289 #ifdef _WIN32
290 closesocket(m_clientSocket);
291 #else
292 close(m_clientSocket);
293 #endif
294 }
295 }
296
297 //---------------------------------------------------------------------
298
299 class DataReceiver final : public TThread::Runnable {
300 public:
DataReceiver(int clientSocket,const QString & data,std::shared_ptr<TTcpIpServerImp> serverImp)301 DataReceiver(int clientSocket, const QString &data,
302 std::shared_ptr<TTcpIpServerImp> serverImp)
303 : m_clientSocket(clientSocket)
304 , m_data(data)
305 , m_serverImp(std::move(serverImp)) {}
306
307 void run() override;
308
309 int m_clientSocket;
310 QString m_data;
311 std::shared_ptr<TTcpIpServerImp> m_serverImp;
312 };
313
314 //---------------------------------------------------------------------
315
run()316 void DataReceiver::run() {
317 m_serverImp->onReceive(m_clientSocket, m_data);
318 #ifdef _WIN32
319 closesocket(m_clientSocket);
320 #else
321 close(m_clientSocket);
322 #endif
323 }
324
325 //---------------------------------------------------------------------
326
run()327 void TTcpIpServer::run() {
328 try {
329 #ifdef _WIN32
330
331 int err = establish(m_imp->m_port, m_imp->m_s);
332 if (!err && m_imp->m_s != -1) {
333 int t; // client socket
334
335 while (!Sthutdown) /* loop for connections */
336 {
337 if ((t = get_connection(m_imp->m_s)) < 0) /* get a connection */
338 {
339 m_exitCode = WSAGetLastError();
340 // GESTIRE LA CONDIZIONE DI ERRORE
341 return;
342 }
343
344 QString data;
345 int ret = m_imp->readData(t, data);
346 if (ret != -1 && data != "") {
347 if (data == QString("shutdown")) {
348 // DebugBreak();
349 Sthutdown = true;
350 } else {
351 // creo un nuovo thread per la gestione dei dati ricevuti
352 TThread::Executor executor;
353 executor.addTask(new DataReceiver(t, data, m_imp));
354 }
355 } else {
356 ::shutdown(t, 1);
357 }
358 }
359 } else {
360 m_exitCode = err;
361 return;
362 }
363
364 #else // !_WIN32
365
366 int err = establish(m_imp->m_port, m_imp->m_s);
367 if (!err && m_imp->m_s != -1) {
368 // signal(SIGCHLD, fireman); /* this eliminates zombies */
369
370 #if defined(MACOSX) || defined(__DragonFly__)
371 struct sigaction sact;
372 sact.sa_handler = shutdown_cb;
373 sigaction(SIGUSR1, &sact, 0);
374 #else
375 sigset(SIGUSR1, shutdown_cb);
376 #endif
377
378 int t;
379
380 while (!Sthutdown) /* loop for connections */
381 {
382 if ((t = get_connection(m_imp->m_s)) < 0) /* get a connection */
383 {
384 if (errno == EINTR) /* EINTR might happen on accept(), */
385 continue; /* try again */
386 perror("accept"); /* bad */
387 m_exitCode = errno;
388 return;
389 }
390
391 TThread::Executor executor;
392 executor.addTask(new DataReader(t, m_imp));
393 }
394 } else {
395 m_exitCode = err;
396 return;
397 }
398
399 #endif // _WIN32
400 } catch (...) {
401 m_exitCode = 2000;
402 return;
403 }
404
405 m_exitCode = 0;
406 }
407
408 //---------------------------------------------------------------------
409
getExitCode() const410 int TTcpIpServer::getExitCode() const { return m_exitCode; }
411
412 //---------------------------------------------------------------------
413
sendReply(int socket,const QString & reply)414 void TTcpIpServer::sendReply(int socket, const QString &reply) {
415 string replyUtf8 = reply.toStdString();
416
417 QString header("#$#THS01.00");
418 header += QString::number((int)replyUtf8.size());
419 header += QString("#$#THE");
420
421 string packet = header.toStdString() + replyUtf8;
422
423 // string packet = reply;;
424
425 int nLeft = packet.size();
426 int idx = 0;
427 while (nLeft > 0) {
428 #ifdef _WIN32
429 int ret = send(socket, packet.c_str() + idx, nLeft, 0);
430 #else
431 int ret = write(socket, packet.c_str() + idx, nLeft);
432 #endif
433
434 if (ret == SOCKET_ERROR) {
435 // Error
436 }
437 nLeft -= ret;
438 idx += ret;
439 }
440
441 ::shutdown(socket, 1);
442 }
443
444 //---------------------------------------------------------------------
445 //---------------------------------------------------------------------
446
establish(unsigned short portnum,int & sock)447 int establish(unsigned short portnum, int &sock) {
448 char myname[MAXHOSTNAME + 1];
449 struct sockaddr_in sa;
450 struct hostent *hp;
451
452 memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */
453 gethostname(myname, MAXHOSTNAME); /* who are we? */
454 hp = gethostbyname(myname); /* get our address info */
455 if (hp == NULL) /* we don't exist !? */
456 return (-1);
457
458 sa.sin_family = hp->h_addrtype; /* this is our host address */
459 sa.sin_port = htons(portnum); /* this is our port number */
460 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */
461 {
462 #ifdef _WIN32
463 int err = WSAGetLastError();
464 return err;
465 #else
466 return errno;
467 #endif
468 }
469
470 if (::bind(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0) {
471 #ifdef _WIN32
472 int err = WSAGetLastError();
473 closesocket(sock);
474 return err;
475 #else
476 return errno;
477 close(sock);
478 #endif
479 }
480
481 return listen(sock, 3); /* max # of queued connects */
482 }
483
484 //-----------------------------------------------------------------------
485 /* wait for a connection to occur on a socket created with establish() */
486
get_connection(int s)487 int get_connection(int s) {
488 int t; /* socket of connection */
489
490 if ((t = accept(s, NULL, NULL)) < 0) /* accept connection if there is one */
491 return (-1);
492 return (t);
493 }
494
495 #ifndef _WIN32
496 //-----------------------------------------------------------------------
497 /* as children die we should get catch their returns or else we get
498 * zombies, A Bad Thing. fireman() catches falling children.
499 */
fireman(int)500 void fireman(int) {
501 while (waitpid(-1, NULL, WNOHANG) > 0)
502 ;
503 }
504 #endif
505