1 //#**************************************************************
2 //#
3 //# filename: TcpIpRoutines.cpp
4 //#
5 //# author: Sch�rgenhumer Markus
6 //#
7 //# generated: Feb and July 2013
8 //#
9 //# description: - base class TCPIPSocket for TCP/IP server/client
10 //# socket set-up, communication, and error handling
11 //# - derived class TCPIPHotInt for use in HOTINT
12 //#
13 //# remarks: - additional linking dependencies: ws2_32.lib
14 //# (in HOTINT in the project "MBSElementsAndModels")
15 //#
16 //# Copyright (c) 2003-2013 Johannes Gerstmayr, Linz Center of Mechatronics GmbH, Austrian
17 //# Center of Competence in Mechatronics GmbH, Institute of Technical Mechanics at the
18 //# Johannes Kepler Universitaet Linz, Austria. All rights reserved.
19 //#
20 //# This file is part of HotInt.
21 //# HotInt is free software: you can redistribute it and/or modify it under the terms of
22 //# the HOTINT license. See folder 'licenses' for more details.
23 //#
24 //# bug reports are welcome!!!
25 //# WWW: www.hotint.org
26 //# email: bug_reports@hotint.org or support@hotint.org
27 //#**************************************************************
28
29
30 #include <fstream>
31 #include <iostream>
32 #include <sstream>
33 #include "TcpIpRoutines.h"
34 #include "winsock2.h" //note: also includes windows.h
35
36 using namespace std;
37
38
39 //========================================================================================
40 //================================== TCPIPSocket =========================================
41 //========================================================================================
42
TCPIPSocket(SocketType typei,char * ipdata,int errormsgflag,int infomsgflag)43 TCPIPSocket::TCPIPSocket(SocketType typei, char* ipdata, int errormsgflag, int infomsgflag)
44 {
45 type=typei;
46 port=0;
47 //ipstring=NULL;
48 status=0;
49 autoreconnect=0;
50 looptime=1000;
51 //recvbuffer=0;
52 SetErrorMessageMode(errormsgflag);
53 SetInfoMessageMode(infomsgflag);
54 GetTCPIPConfig(ipdata);
55 accepttimeout = -1;
56 }
57
TCPIPSocket(SocketType typei,char * ipIn,unsigned short portIn,int errormsgflag,int infomsgflag)58 TCPIPSocket::TCPIPSocket(SocketType typei, char* ipIn, unsigned short portIn, int errormsgflag, int infomsgflag)
59 {
60 Set(typei,ipIn,portIn,errormsgflag,infomsgflag);
61 }
62
Set(SocketType typei,char * ipIn,unsigned short portIn,int errormsgflag,int infomsgflag)63 void TCPIPSocket::Set(SocketType typei, char* ipIn, unsigned short portIn, int errormsgflag, int infomsgflag)
64 {
65 type=typei;
66 port=portIn;
67 //ipstring=ipIn;
68 strcpy(ipstring,ipIn);
69 status=0;
70 autoreconnect=0;
71 looptime=1000;
72 SetErrorMessageMode(errormsgflag);
73 SetInfoMessageMode(infomsgflag);
74 accepttimeout = -1;
75 }
76
77
SetUpConnection()78 int TCPIPSocket::SetUpConnection()
79 {
80 if(status)
81 CloseConnection();
82
83 if(type==ST_client)
84 {
85 StartWinsock();
86 CreateSocket();
87 //ConnectOnce();
88 ConnectLoop();
89 //FlushRecvBuffer();
90 Initialize();
91 return 1;
92 }
93 else if(type==ST_server)
94 {
95 StartWinsock();
96 CreateSocket();
97 BindSocket();
98 ListenMode();
99 AcceptConnection();
100 Initialize();
101 return 1;
102 }
103 else
104 {
105 Error(0,"Invalid socket type!");
106 return -1;
107 }
108 }
109
CloseConnection()110 void TCPIPSocket::CloseConnection()
111 {
112 if(status)
113 {
114 closesocket(c);
115 if(type==ST_server)
116 closesocket(s);
117 WSACleanup();
118 status = 0;
119 }
120 }
121
~TCPIPSocket()122 TCPIPSocket::~TCPIPSocket()
123 {
124 CloseConnection();
125 //if(ipstring)
126 // delete [] ipstring;
127 }
128
129
GetTCPIPConfig(char * file)130 void TCPIPSocket::GetTCPIPConfig(char* file)
131 {
132 ifstream ipconfig;
133 string a1,a2,a3,a4,temp1;
134
135 ipconfig.open(file,ios::binary|ios::in);
136 if(!ipconfig.is_open())
137 {
138 Error(0,string("Access to TCP/IP configuration file '").append(string(file)).append(string("' failed!")));
139 //cout << "Error accessing 'IP.txt'" << endl;
140 //cout << "Enter configuration manually: " << endl << endl;
141 //cout << "Server-IP a1.a2.a3.a4 (IPv4): " << endl << endl;
142 //cout << "a1: ";
143 //cin >> a1;
144 //cout << "a2: ";
145 //cin >> a2;
146 //cout << "a3: ";
147 //cin >> a3;
148 //cout << "a4: ";
149 //cin >> a4;
150 //cout << "Port: ";
151 //cin >> port;
152 //cout << endl;
153 }
154 else
155 {
156 ipconfig >> a1;
157 ipconfig >> a2;
158 ipconfig >> a3;
159 ipconfig >> a4;
160 ipconfig >> port;
161 ipconfig.clear();
162 ipconfig.close();
163 }
164
165 temp1.append(a1).append(".").append(a2).append(".").append(a3).append(".").append(a4);
166 //ipstring = new char[temp1.length()+1]; //generation of a c-strings for the IP
167 strcpy(ipstring,temp1.c_str());
168
169 //stringstream out;
170 //out << "server-IP / port: " << ipstring << " / " << port << endl << endl;
171 //InfoMessage(out.str());
172 }
173
StartWinsock()174 long TCPIPSocket::StartWinsock(){
175 WSADATA wsa;
176 long rc = WSAStartup(MAKEWORD(2,0),&wsa); //MAKEWORD ... macro which transforms the version number 2.0 into WORD (unsigned short)
177 if(rc)
178 Error(1,"Failed to start winsock!",rc);
179 else
180 InfoMessage("Winsock started");
181 return rc;
182 }
183
CreateSocket()184 void TCPIPSocket::CreateSocket()
185 {
186 //SOCKET & loc = s; //somehow, this reference IS NOT WORKING, no clue why; workaround below the commented lines
187 //if(type==ST_client)
188 // loc=c;
189 //loc=socket(AF_INET,SOCK_STREAM,0);
190 //if(loc==INVALID_SOCKET)
191 // Error(1,"Failed to create socket!\n",WSAGetLastError());
192 //else
193 // InfoMessage("Socket created\n");
194
195 if(type==ST_client)
196 {
197 c=socket(AF_INET,SOCK_STREAM,0);
198 if(c==INVALID_SOCKET)
199 Error(1,"Failed to create socket!",WSAGetLastError());
200 else
201 InfoMessage("Socket created");
202 }
203 else
204 {
205 s=socket(AF_INET,SOCK_STREAM,0);
206 if(s==INVALID_SOCKET)
207 Error(1,"Failed to create socket!",WSAGetLastError());
208 else
209 InfoMessage("Socket created");
210 }
211 }
212
BindSocket()213 long TCPIPSocket::BindSocket()
214 {
215 SOCKADDR_IN addr;
216 long rc;
217
218 memset(&addr,0,sizeof(SOCKADDR_IN)); //cf. p.19, Beej's guide
219 addr.sin_family=AF_INET; //IPv4
220 addr.sin_port=htons(port);
221 addr.sin_addr.s_addr=inet_addr(ipstring);
222 rc=bind(s,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
223 if(rc==SOCKET_ERROR)
224 Error(1,"Failed to bind server socket to given IP and port!",WSAGetLastError());
225 else
226 {
227 stringstream out;
228 out << "Server socket bound to IP " << ipstring << ", port " << port;
229 InfoMessage(out.str());
230 }
231 return rc;
232 }
233
ListenMode()234 long TCPIPSocket::ListenMode()
235 {
236 long rc;
237 rc=listen(s,10);
238 if(rc==SOCKET_ERROR)
239 Error(1,"Failed to activate listen mode!",WSAGetLastError());
240 else
241 InfoMessage("Server socket is in listen mode...");
242 return rc;
243 }
244
AcceptConnection()245 int TCPIPSocket::AcceptConnection()
246 {
247 if(accepttimeout>0)
248 {
249 int i=0;
250 while(1)
251 {
252 //workaround to implement timeout for accept
253
254 //from MSDN on the "select"-function:
255 //The parameter readfds identifies the sockets that are to be checked for readability. If the socket is currently in the listen state, it will be marked as readable
256 //if an incoming connection request has been received such that an accept is guaranteed to complete without blocking.
257
258 timeval to;
259 to.tv_sec = (unsigned int) ((double)accepttimeout)/1000;
260 to.tv_usec = accepttimeout%1000;
261 fd_set socketset;
262 socketset.fd_count = 1;
263 socketset.fd_array[0] = s;
264 //FD_ZERO(&socketset);
265 //FD_SET(c,&socketset);
266 int temp = select(1,&socketset,NULL,NULL,&to);
267 if(temp==0)
268 {
269 ++i;
270 if(i<3)
271 Message("Failed to accept connection from client! (timeout) Retry...");
272 else
273 Error(1,"Failed to accept connection from client! (timeout)");
274 }
275 else if(temp==SOCKET_ERROR)
276 Error(1,"Failed to accept connection from client!",WSAGetLastError());
277 else
278 break;
279 }
280 }
281
282 c=accept(s,NULL,NULL);
283 if(c==INVALID_SOCKET)
284 Error(1,"Failed to accept connection from client!",WSAGetLastError());
285 else
286 {
287 InfoMessage("New connection to client accepted");
288 status=1;
289 }
290 return 1;
291 }
292
ConnectLoop()293 long TCPIPSocket::ConnectLoop()
294 {
295 long rc;
296 SOCKADDR_IN addr; //addr contains all neccessary information about the server socket; the port of the client socket is chosen by Windows
297 stringstream out;
298
299 memset(&addr,0,sizeof(SOCKADDR_IN)); //reset everything to 0
300 addr.sin_family=AF_INET;
301 addr.sin_port=htons(port); //port
302 addr.sin_addr.s_addr=inet_addr(ipstring); //IP v4 adress of server
303
304 int waitingcounter = -1;
305 while(1){
306 rc=connect(c,(SOCKADDR*)&addr,sizeof(SOCKADDR));
307 if(rc==SOCKET_ERROR)
308 {
309 switch(waitingcounter){
310 case -1: out.str(""); out << "Waiting to connect to " << ipstring << ", port " << port << endl; break;
311 case 0: out.str(""); out << "\r." << " "; break;
312 case 1: out.str(""); out << "\r.." << " "; break;
313 case 2: out.str(""); out << "\r..." << " "; waitingcounter = -1; break;
314 }
315 InfoMessage(out.str());
316 ++waitingcounter;
317 Sleep(looptime); //wait for "time" milliseconds
318 }
319 else
320 {
321 InfoMessage("Connected!");
322 status=1;
323 break;
324 }
325 }
326 return rc;
327 }
328
ConnectOnce()329 long TCPIPSocket::ConnectOnce()
330 {
331 long rc;
332 SOCKADDR_IN addr; //addr contains all neccessary information about the server socket; the port of the client socket is chosen by Windows
333
334 memset(&addr,0,sizeof(SOCKADDR_IN)); //reset everything to 0
335 addr.sin_family=AF_INET;
336 addr.sin_port=htons(port); // port
337 addr.sin_addr.s_addr=inet_addr(ipstring); //IP v4 adress of server
338 rc=connect(c,(SOCKADDR*)&addr,sizeof(SOCKADDR));
339
340 if(rc==SOCKET_ERROR)
341 Error(1,"Connect failed!",WSAGetLastError());
342 else
343 {
344 InfoMessage("Connected!");
345 status=1;
346 }
347 return rc;
348 }
349
350 //void TCPIPSocket::FlushRecvBuffer()
351 //{
352 // int bufsize;
353 // int optlen=sizeof(int);
354 // getsockopt(c,sol_socket,so_rcvbuf,reinterpret_cast<char*> (&bufsize),&optlen);
355 // //cout << "recv buffer in bytes: " << temp << "\n";
356 // char* temp = new char[bufsize];
357 //
358 // //unsigned long recvto;
359 // //optlen=sizeof(unsigned long);
360 // //getsockopt(c,sol_socket,so_rcvtimeo,reinterpret_cast<char*> (&recvto),&optlen);
361 // //cout << "timeout " << recvto << "\n";
362 //
363 // setrecvtimeout(10000);
364 //
365 // int remain=bufsize;
366 // int tmp=0;
367 // int count=0;
368 // while(remain!=0 && tmp>=0)
369 // {
370 // int tmp = recv(c,temp+(bufsize-remain),remain,0);
371 // remain-=tmp;
372 // count+=tmp;
373 // }
374 //
375 // cout << "from buffer: " << count << "\n";
376 // cout << "last error" << wsagetlasterror() << "\n";
377 //
378 // //setrecvtimeout(recvto);
379 //
380 // delete [] temp;
381 //}
382
Initialize()383 void TCPIPSocket::Initialize()
384 {
385 }
386
SendByte(byte data)387 int TCPIPSocket::SendByte(byte data)
388 {
389 int stat = SendData(reinterpret_cast<char*> (&data),1);
390 return stat;
391 }
392
RecvByte(byte & data)393 int TCPIPSocket::RecvByte(byte & data)
394 {
395 int stat = RecvData(reinterpret_cast<char*> (&data),1);
396 return stat;
397 }
398
SendInteger(int data)399 int TCPIPSocket::SendInteger(int data)
400 {
401 int temp=htonl(data);
402 int stat = SendData(reinterpret_cast<char*> (&temp),4);
403 return stat;
404 }
405
RecvInteger(int & datain)406 int TCPIPSocket::RecvInteger(int & datain)
407 {
408 datain=0;
409 int stat = RecvData(reinterpret_cast<char*> (&datain),4);
410 datain=ntohl(datain);
411 return stat;
412 }
413
SendData(char * data,int size)414 int TCPIPSocket::SendData(char* data, int size)
415 {
416 if(!status)
417 {
418 Error(1,"Failed to send data. Socket is not properly initialized!");
419 return -1;
420 }
421
422 int remain=size;
423 int tmp=0;
424
425 while(remain!=0)
426 {
427 int tmp = send(c,data+(size-remain),remain,0);
428 if(tmp<=0)
429 {
430 Error(1,"An error occurred while sending data!",WSAGetLastError());
431 return tmp;
432 }
433 remain-=tmp;
434 }
435 return size;
436 }
437
RecvData(char * data,int size)438 int TCPIPSocket::RecvData(char* data, int size)
439 {
440 if(!status)
441 {
442 Error(1,"Failed to receive data. Socket is not properly initialized!");
443 return -1;
444 }
445
446 int remain=size;
447 int tmp=0;
448
449 while(remain!=0)
450 {
451 int tmp = recv(c,data+(size-remain),remain,0);
452 //if(tmp==0)
453 //{
454 // Error(1,"Connection was closed by the server!");
455 // return tmp;
456 //}
457 if(tmp<=0)
458 {
459 Error(1,"An error occurred while receiving data!",WSAGetLastError());
460 return tmp;
461 }
462 remain-=tmp;
463 }
464 return size;
465 }
466
SetRecvTimeOut(unsigned long time)467 void TCPIPSocket::SetRecvTimeOut(unsigned long time)
468 {
469 setsockopt(c,SOL_SOCKET,SO_RCVTIMEO,reinterpret_cast<const char*> (&time),sizeof(unsigned long));
470 }
471
SetSendTimeOut(unsigned long time)472 void TCPIPSocket::SetSendTimeOut(unsigned long time)
473 {
474 setsockopt(c,SOL_SOCKET,SO_SNDTIMEO,reinterpret_cast<const char*> (&time),sizeof(unsigned long));
475 }
476
SetAcceptTimeOut(unsigned long time)477 void TCPIPSocket::SetAcceptTimeOut(unsigned long time)
478 {
479 accepttimeout = time;
480 }
481
482 //void TCPIPSocket::SetRecvBufferSize(int size)
483 //{
484 // recvbuffer=size;
485 // setsockopt(c,SOL_SOCKET,SO_RCVBUF,reinterpret_cast<const char*> (&recvbuffer),sizeof(int));
486 //}
487
SetLoopTime(int time)488 void TCPIPSocket::SetLoopTime(int time)
489 {
490 looptime=time;
491 }
492
Error(int type,string err,int errornumber)493 int TCPIPSocket::Error(int type, string err, int errornumber)
494 {
495 stringstream ts;
496 if(type==0)
497 {
498 if(errormsg)
499 {
500 string temp = "Fatal error: ";
501 if(errornumber)
502 {
503 ts<<errornumber;
504 temp.append(ts.str());
505 }
506 temp.append("\n");
507 std::cout << temp;
508 std::cout << err << "\n";
509 system("PAUSE");
510 }
511 exit(-1);
512 }
513 else if(type==1)
514 {
515 if(errormsg)
516 {
517 string temp="Error: ";
518 if(errornumber)
519 {
520 ts<<errornumber;
521 temp.append(ts.str());
522 }
523 temp.append("\n");
524 std::cout << temp;
525 std::cout << err << "\n";
526 system("PAUSE");
527 }
528 CloseConnection();
529 if(autoreconnect)
530 {
531 InfoMessage("Re-initializing TCP/IP connection...");
532 SetUpConnection();
533 }
534 }
535 return errornumber;
536 }
537
Message(string message)538 void TCPIPSocket::Message(string message)
539 {
540 cout << message << endl;
541 }
542
InfoMessage(string info)543 void TCPIPSocket::InfoMessage(string info)
544 {
545 if(infomsg)
546 cout << info << endl;
547 }
548
SetErrorMessageMode(int flag)549 void TCPIPSocket::SetErrorMessageMode(int flag)
550 {
551 if(flag)
552 errormsg=1;
553 else
554 errormsg=0;
555 }
556
SetInfoMessageMode(int flag)557 void TCPIPSocket::SetInfoMessageMode(int flag)
558 {
559 if(flag)
560 infomsg=1;
561 else
562 infomsg=0;
563 }
564
SetAutoReconnect(int flag)565 void TCPIPSocket::SetAutoReconnect(int flag)
566 {
567 if(flag)
568 autoreconnect=1;
569 else
570 autoreconnect=0;
571 }
572
573
574 //========================================================================================
575 //=================================== TCPIPHotInt ========================================
576 //========================================================================================
577
Set(SocketType typei,char * ipIn,unsigned short portIn,int errormsgflag,int infomsgflag)578 void TCPIPHotInt::Set(SocketType typei, char* ipIn, unsigned short portIn, int errormsgflag, int infomsgflag)
579 {
580 TCPIPSocket::Set(typei,ipIn,portIn,errormsgflag,infomsgflag);
581 }
582
Set(MBS * mbsI,SocketType typei,char * ipIn,unsigned short portIn,int errormsgflag,int infomsgflag)583 void TCPIPHotInt::Set(MBS* mbsI, SocketType typei, char* ipIn, unsigned short portIn, int errormsgflag, int infomsgflag)
584 {
585 mbs=mbsI;
586 TCPIPSocket::Set(typei,ipIn,portIn,errormsgflag,infomsgflag);
587 }
588
Error(int type,std::string err,int errornumber)589 int TCPIPHotInt::Error(int type, std::string err, int errornumber)
590 {
591 stringstream ts;
592 if(errormsg)
593 {
594 string temp = "TCP/IP error: ";
595 temp.append(err);
596 if(errornumber)
597 {
598 temp.append(" (");
599 ts<<errornumber;
600 temp.append(ts.str());
601 temp.append(")\n");
602 }
603
604 mbs->UO().InstantMessageText(temp.c_str());
605 assert(0);
606 exit(0);
607 }
608 return errornumber;
609 }
610
Message(std::string message)611 void TCPIPHotInt::Message(std::string message)
612 {
613 mbs->UO() << message.c_str() << "\n";
614 }
615
InfoMessage(std::string info)616 void TCPIPHotInt::InfoMessage(std::string info)
617 {
618 mbs->UO() << info.c_str() << "\n";
619 }
620