PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/gnu-cpp/core/src/wsb-libstd/connector/TCPConnector.cpp

https://bitbucket.org/osi/wsb-core
C++ | 505 lines | 226 code | 134 blank | 145 comment | 68 complexity | a8dd09ed7af6e6202084bfea00619103 MD5 | raw file
  1. /*
  2. * TCPConnector.cpp
  3. *
  4. * Created on: Dec 2, 2011
  5. * Author: rleys
  6. */
  7. // Includes
  8. //----------------------
  9. //-- Std
  10. #include <string>
  11. #include <cstring>
  12. #include <cerrno>
  13. #include <cstdio>
  14. using namespace std;
  15. //-- Common
  16. #include <wsb-core/common/URI.h>
  17. #include <wsb-core/common/Logging.h>
  18. //-- Network
  19. #include <wsb-core/network/AbstractConnector.h>
  20. #include <wsb-core/network/ConnectorException.h>
  21. //-- Unix socket
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <sys/un.h>
  25. #include <netinet/in.h>
  26. #include <netdb.h>
  27. #include <poll.h>
  28. #include <unistd.h>
  29. #include "TCPConnector.h"
  30. namespace OSI {
  31. namespace WSB {
  32. TCPConnector::TCPConnector(string url) throw (ConnectorException)
  33. : AbstractConnector(url) {
  34. //-- Defaults
  35. this->socketDescriptor = 0;
  36. this->socketType = 0;
  37. //-- Init peer sockets semaphore
  38. sem_init(&(this->peerSocketCreated), 0, 0);
  39. //-- Init Client socket connectors array
  40. //bzero(&(this->clientSockets),128*sizeof(int));
  41. //-- Verify the scheme be tcp or tcps
  42. /* if (this->getURI()->getScheme()!="tcp" && this->getURI()->getScheme()!="tcps") {
  43. throw ConnectorException("Scheme can only be tcp or tcps");
  44. }*/
  45. }
  46. TCPConnector::~TCPConnector() {
  47. // TODO Auto-generated destructor stub
  48. }
  49. void TCPConnector::reload() {
  50. }
  51. void TCPConnector::init() {
  52. // Create The socket
  53. //---------------------------
  54. //-- Make TCP/IP connection
  55. if (this->getURI()->getHost().length()>0) {
  56. this->socketDescriptor = socket(PF_INET,SOCK_STREAM,0);
  57. this->socketType = PF_INET;
  58. } else if (this->getURI()->getPath().length()>0) {
  59. this->socketDescriptor = socket(PF_LOCAL,SOCK_STREAM,0);
  60. this->socketType = PF_LOCAL;
  61. } else {
  62. //-- No Host/File path description
  63. throw ConnectorException("URI "+this->getURI()->getURI()+" does not describe a Host or File path with which to create a socket");
  64. }
  65. if (!this->socketDescriptor) {
  66. perror("Could not create socket");
  67. }
  68. // Parent call
  69. //-----------------------
  70. AbstractConnector::init();
  71. }
  72. void TCPConnector::stop() {
  73. this->getLogger("network.connector.tcp")->infoStream() << "Closing Connector";
  74. //-- Stop socket
  75. shutdown(this->socketDescriptor,SHUT_RDWR);
  76. close(this->socketDescriptor);
  77. //-- Stop thread
  78. Thread::stop();
  79. }
  80. void TCPConnector::finish() {
  81. //-- Stop socket
  82. //close(this->socketDescriptor);
  83. //-- Stop thread
  84. Thread::finish();
  85. }
  86. void TCPConnector::run() {
  87. //--------------------------
  88. // Server
  89. //--------------------------
  90. if (this->getDirection() == AbstractConnector::SERVER) {
  91. // Prepare server address
  92. //------------------------------
  93. struct sockaddr * address = NULL;
  94. //-- INET
  95. if (this->socketType==PF_INET) {
  96. //-- IP address bzw hostname
  97. struct sockaddr_in iaddress;
  98. iaddress.sin_family = AF_INET;
  99. iaddress.sin_addr.s_addr = INADDR_ANY;
  100. if (this->getURI()->getPort()>0) {
  101. iaddress.sin_port = htons(this->getURI()->getPort());
  102. } else
  103. iaddress.sin_port = htons(CONNECTOR_TCP_DEFAULT_PORT);
  104. Logging::getLogger("network.connector.tcp.server")->infoStream() << "Starting INET TCP connector on port " << ntohs(iaddress.sin_port) ;
  105. address = (struct sockaddr*) calloc(1,sizeof(struct sockaddr_in));
  106. memccpy(address,&iaddress,1,sizeof(struct sockaddr_in));
  107. }
  108. //-- Unix
  109. else if (this->socketType==PF_LOCAL) {
  110. //-- Unix Address
  111. struct sockaddr_un uaddress;
  112. uaddress.sun_family = AF_UNIX;
  113. snprintf(uaddress.sun_path, 108, "s%",this->getURI()->getPath().c_str());
  114. Logging::getLogger("network.connector.tcp.server")->infoStream() << "Starting Local TCP connector" ;
  115. } else {
  116. //-- Don't start
  117. return;
  118. }
  119. // Bind the socket and listen
  120. //----------------------
  121. int reUseAddress = 1;
  122. setsockopt(this->socketDescriptor,SOL_SOCKET,SO_REUSEADDR,&reUseAddress,sizeof(int));
  123. //-- Do bind
  124. if (bind(this->socketDescriptor,(const sockaddr*)address,sizeof(struct sockaddr))==-1) {
  125. perror("Could not bind socket");
  126. }
  127. listen(this->socketDescriptor,100);
  128. // Select:
  129. // - accept event on main socket
  130. // - doReceive to make a receive round on the connected sockets
  131. //---------------------------
  132. this->signalStarted();
  133. // Start Looping
  134. while (!this->stopRequested()) {
  135. //-- Create Sockets to be polled array:
  136. //-- * 0 = main socketDescriptor for connections
  137. //-- * 1-... = connected client sockets
  138. int socketsCount = this->peerSockets.size()+1; // Number of clients to dynamically adjust polled sockets
  139. struct pollfd fds[socketsCount];
  140. //struct pollfd * fds = (struct pollfd * ) calloc(socketsCount,sizeof(struct pollfd));
  141. // Add Local server socket for connection accept
  142. fds[0].fd = this->socketDescriptor;
  143. fds[0].events = POLLIN;
  144. // Add peer sockets
  145. int peersCount = 0;
  146. for ( map<int,int>::iterator it = this->peerSockets.begin(); it != this->peerSockets.end(); it++) {
  147. fds[peersCount+1].fd = it->second;
  148. fds[peersCount+1].events = POLLIN;
  149. peersCount++;
  150. }
  151. //-- Poll
  152. int pollres = ::poll(fds, socketsCount, -1);
  153. //-- res < 0 -> error -> quit
  154. if (pollres<0) {
  155. Logging::getLogger("network.connector.tcp.server")->errorStream() << "Polling returned an error " << strerror(errno);
  156. break;
  157. }
  158. //-- res == 0 -> nothing then loop
  159. else if (pollres==0) {
  160. continue;
  161. }
  162. //-- res > 0 -> loop on array to answer to events on various sockets
  163. else {
  164. for (int i = 0 ; i < socketsCount ; i++) {
  165. struct pollfd fd = fds[i];
  166. //-- Error or nothing
  167. if ( (fd.revents & POLLERR) || (fd.revents &POLLHUP) || (fd.revents & POLLNVAL)) {
  168. continue;
  169. }
  170. //-- POLLIN on main socket descriptor indicates connection
  171. else if ( (fd.revents &POLLIN) && fd.fd == this->socketDescriptor) {
  172. struct sockaddr_in clientAddress;
  173. socklen_t clientAddressLength = sizeof(struct sockaddr_in);
  174. int connectionResult = accept(this->socketDescriptor,(sockaddr*)&clientAddress,&clientAddressLength);
  175. if (connectionResult>=0) {
  176. // Connection Accepted -> Record socket in sockets list
  177. //------------------
  178. Logging::getLogger("network.connector.tcp.server")->infoStream() << "Client Connection accepted: " << connectionResult ;
  179. //-- Get Client port
  180. int local_port = 0;
  181. struct sockaddr_in client_sin;
  182. unsigned int client_addrlen = sizeof(client_sin);
  183. if(getsockname(connectionResult, (struct sockaddr *)&client_sin, &client_addrlen) == 0)
  184. {
  185. local_port = ntohs(clientAddress.sin_port);
  186. }
  187. //-- Record Socket descriptor in peer map
  188. this->peerSockets[local_port] = connectionResult;
  189. sem_post(&(this->peerSocketCreated));
  190. }
  191. }
  192. //-- POLLIN on another socket -> receive
  193. else if ( fd.revents &POLLIN) {
  194. Logging::getLogger("network.connector.tcp.server")->infoStream() << "Data available on socket: " << fd.fd ;
  195. // Find back port
  196. int port = 0 ;
  197. for (map<int, int>::iterator it = this->peerSockets.begin();
  198. it != this->peerSockets.end(); it++) {
  199. if (it->second == fd.fd) {
  200. port = it->first;
  201. break;
  202. }
  203. }
  204. this->doReceive(fd.fd,port);
  205. }
  206. }
  207. }
  208. // EOF wait on stop
  209. }
  210. //int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  211. // Accept connections
  212. //-----------------
  213. /*Logging::getLogger("network.connector.tcp.server")->infoStream() << "Accepting connections ";
  214. this->signalStarted();
  215. struct sockaddr_in clientAddress;
  216. socklen_t clientAddressLength = sizeof(struct sockaddr_in);
  217. int connectionResult = accept(this->socketDescriptor,(sockaddr*)&clientAddress,&clientAddressLength);
  218. if (connectionResult>=0) {
  219. // Connection Accepted -> Start client Thread
  220. //------------------
  221. Logging::getLogger("network.connector.tcp.server")->infoStream() << "Client Connection accepted: " << connectionResult ;
  222. //-- Get Client port
  223. int local_port = 0;
  224. struct sockaddr_in client_sin;
  225. unsigned int client_addrlen = sizeof(client_sin);
  226. if(getsockname(connectionResult, (struct sockaddr *)&client_sin, &client_addrlen) == 0)
  227. {
  228. local_port = ntohs(clientAddress.sin_port);
  229. }
  230. //-- Record Socket descriptor
  231. this->peerSockets[local_port] = connectionResult;
  232. this->doReceive();
  233. } else {
  234. Logging::getLogger("network.connector.tcp.server")->infoStream() << "Closing TCP connector" ;
  235. }*/
  236. }
  237. //--------------------------
  238. // Client (same as server, without connect accepting polling)
  239. //--------------------------
  240. else {
  241. Logging::getLogger("network.connector.tcp.client")->infoStream() << "Starting receiving" ;
  242. //this->doReceive();
  243. // Select:
  244. // - doReceive to make a receive round on the connected sockets
  245. //---------------------------
  246. // Start Looping
  247. while (!this->stopRequested()) {
  248. // If no peers -> wait for one to be offered
  249. //-----------------
  250. if (this->peerSockets.size()==0) {
  251. sem_wait(&(this->peerSocketCreated));
  252. } else {
  253. // Try to get something from semaphore to be sure it is empty
  254. sem_trywait(&(this->peerSocketCreated));
  255. }
  256. Logging::getLogger("network.connector.tcp.client")->infoStream() << "There are some peer sockets to receive on: " << this->peerSockets.size() ;
  257. //-- Create Sockets to be polled array:
  258. //-- * 0 = main socketDescriptor for connections
  259. //-- * 1-... = connected client sockets
  260. int socketsCount = this->peerSockets.size(); // Number of clients to dynamically adjust polled sockets
  261. struct pollfd fds[socketsCount];
  262. //struct pollfd * fds = (struct pollfd * ) calloc(socketsCount,sizeof(struct pollfd));
  263. // Add peer sockets
  264. int peersCount = 0;
  265. for ( map<int,int>::iterator it = this->peerSockets.begin(); it != this->peerSockets.end(); it++) {
  266. fds[peersCount].fd = it->second;
  267. fds[peersCount].events = POLLIN;
  268. peersCount++;
  269. }
  270. //-- Poll
  271. int pollres = ::poll(fds, socketsCount, -1);
  272. //-- res < 0 -> error -> quit
  273. if (pollres<0) {
  274. Logging::getLogger("network.connector.tcp.client")->errorStream() << "Polling returned an error " << strerror(errno);
  275. break;
  276. }
  277. //-- res == 0 -> nothing then loop
  278. else if (pollres==0) {
  279. continue;
  280. }
  281. //-- res > 0 -> loop on array to answer to events on various sockets
  282. else {
  283. for (int i = 0 ; i < socketsCount ; i++) {
  284. struct pollfd fd = fds[i];
  285. //-- Error or nothing -> remove peer
  286. if ( (fd.revents & POLLERR) || (fd.revents &POLLHUP) || (fd.revents & POLLNVAL)) {
  287. Logging::getLogger("network.connector.tcp.client")->errorStream() << "Seen error on peer socket -> erasing it ";
  288. for (map<int, int>::iterator it = this->peerSockets.begin();
  289. it != this->peerSockets.end(); it++) {
  290. if (it->second == fd.fd) {
  291. this->peerSockets.erase(it);
  292. break;
  293. }
  294. }
  295. continue;
  296. }
  297. //-- POLLIN on another socket -> receive
  298. else if ( fd.revents &POLLIN) {
  299. // Find back port
  300. int port = 0 ;
  301. for (map<int, int>::iterator it = this->peerSockets.begin();
  302. it != this->peerSockets.end(); it++) {
  303. if (it->second == fd.fd) {
  304. port = it->first;
  305. break;
  306. }
  307. }
  308. Logging::getLogger("network.connector.tcp.client")->infoStream() << "Data available on socket: " << fd.fd ;
  309. this->doReceive(fd.fd,port);
  310. }
  311. }// EOF Loop on sockets after polling
  312. }// EOF Polling succeeded
  313. }// EOF main loop
  314. }
  315. // EOF Client
  316. }
  317. void TCPConnector::maintainConnection(NetworkContext * networkContext){
  318. // If no socket descriptor set -> client
  319. //-------------------------
  320. if (this->connectorDirection == AbstractConnector::CLIENT && networkContext->getNetworkState() == NetworkContext::DEAD) {
  321. // Connection port is the one in the URI or the default one
  322. int connectionPort = networkContext->getURI()->getPort()==0 ? CONNECTOR_TCP_DEFAULT_PORT : networkContext->getURI()->getPort();
  323. // Do we have a peer socket registered ?
  324. if (this->peerSockets.count(connectionPort)>0) {
  325. // Already Connected!
  326. // Status is ALIVE
  327. networkContext->setNetworkState(NetworkContext::ALIVE);
  328. return;
  329. }
  330. //-- Not already connected
  331. Logging::getLogger("network.connector.tcp.client")->infoStream() << " Opening connection to: " << networkContext->getURI()->getURI()<< ",port: " << connectionPort ;
  332. //-- Prepare Server address
  333. struct sockaddr_in serverAddress;
  334. struct hostent * server;
  335. serverAddress.sin_family = AF_INET;
  336. server = gethostbyname(networkContext->getURI()->getHost().c_str());
  337. // Copy address
  338. memcpy(&( serverAddress.sin_addr.s_addr),server->h_addr_list[0],server->h_length*sizeof(char)) ;
  339. // Port
  340. serverAddress.sin_port = htons(connectionPort);
  341. //-- Open Connection
  342. //-- Make TCP/IP connection
  343. int peerSocketDescriptor = socket(PF_INET,SOCK_STREAM,0);
  344. int connectionResult = connect(peerSocketDescriptor,(struct sockaddr*)&serverAddress,sizeof(struct sockaddr_in));
  345. if (connectionResult <0 ) {
  346. Logging::getLogger("network.connector.tcp.client")->fatalStream()
  347. << "Error while Connecting to server: " << strerror(errno) ;
  348. perror ("Could not connect to server");
  349. } else {
  350. //-- Register in peer connection
  351. this->peerSockets[connectionPort] = peerSocketDescriptor;
  352. sem_post(&(this->peerSocketCreated));
  353. //-- Status is ALIVE
  354. networkContext->setNetworkState(NetworkContext::ALIVE);
  355. //-- Start thread for receiving
  356. //this->start();
  357. }
  358. }
  359. }
  360. } /* namespace WSB */
  361. } /* namespace OSI */