source: flair-src/trunk/lib/FlairCore/src/TcpSocket.cpp@ 230

Last change on this file since 230 was 230, checked in by Sanahuja Guillaume, 4 years ago

modifs timeout tcpsocket

File size: 7.3 KB
Line 
1// %flair:license{
2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
4// %flair:license}
5// created: 2015/04/28
6// filename: TcpSocket.cpp
7//
8// author: Gildas Bayard
9// Copyright Heudiasyc UMR UTC/CNRS 7253
10//
11// version: $Id: $
12//
13// purpose: Class defining a TCP socket
14//
15//
16/*********************************************************************/
17#include "TcpSocket.h"
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <arpa/inet.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <string.h>
24
25using std::string;
26
27namespace flair {
28namespace core {
29
30TcpSocket::TcpSocket(const Object *parent, const std::string name,
31 bool _blockOnSend, bool _blockOnReceive)
32 : ConnectedSocket(parent, name), isConnected(false) {
33 blockOnSend = _blockOnSend;
34 blockOnReceive = _blockOnReceive;
35}
36
37TcpSocket::~TcpSocket() {
38 // Info("Debug: destroying TCP socket %s", ObjectName().c_str());
39 close(socket);
40}
41
42void TcpSocket::Listen(const unsigned int port,
43 const std::string localAddress) {
44 socket = ::socket(AF_INET, SOCK_STREAM, 0);
45
46 sockaddr_in my_addr;
47 my_addr.sin_family = AF_INET;
48 my_addr.sin_port = htons(port);
49 if (localAddress == "ANY") {
50 my_addr.sin_addr.s_addr = INADDR_ANY;
51 } else {
52 inet_aton(localAddress.c_str(), &(my_addr.sin_addr));
53 }
54 memset(&(my_addr.sin_zero), '\0', 8);
55
56 if (bind(socket, (sockaddr *)&my_addr, sizeof(my_addr)) < 0) {
57 char errorMsg[256];
58 Err("TCP bind, %s\n", strerror_r(errno, errorMsg, sizeof(errorMsg)));
59 }
60
61 listen(socket, 1);
62}
63
64TcpSocket *TcpSocket::Accept(Time timeout) {
65 TcpSocket *acceptedSocket = nullptr;
66
67 struct timeval tv;
68 if (timeout != 0) {
69 tv.tv_sec = timeout / 1000; // timeout is in ms
70 tv.tv_usec = (timeout % 1000) * 1000;
71 }
72 fd_set rset;
73 FD_ZERO(&rset);
74 FD_SET(socket, &rset);
75 int ret = select(socket + 1, &rset, nullptr, nullptr,
76 (timeout == 0) ? nullptr : &tv); // man 2 accept
77 if (ret < 0) {
78 char errorMsg[256];
79 Err("select: %s\n", strerror_r(errno, errorMsg, sizeof(errorMsg)));
80 } else {
81 if (ret == 0) {
82 // timeout reached
83 // Err("timeout reached\n");
84 } else {
85 // our socket is readable, a new connection can be accepted
86 acceptedSocket = new TcpSocket(this->Parent(), this->ObjectName(),
87 blockOnSend, blockOnReceive);
88 sockaddr_in their_addr;
89 socklen_t namelen = sizeof(their_addr);
90 if ((acceptedSocket->socket =
91 accept(socket, (sockaddr *)&their_addr, &namelen)) < 0) {
92 char errorMsg[256];
93 Err("error: %s\n", strerror_r(errno, errorMsg, sizeof(errorMsg)));
94 delete acceptedSocket;
95 acceptedSocket = nullptr;
96 }
97 }
98 }
99
100 return acceptedSocket;
101}
102
103bool TcpSocket::Connect(const unsigned int distantPort,
104 const std::string distantAddress, Time timeout) {
105 bool success = false;
106
107 if (isConnected) {
108 if (this->distantPort == distantPort &&
109 this->distantAddress == distantAddress) {
110 return true;
111 } else {
112 close(socket);
113 }
114 }
115 socket = ::socket(AF_INET, SOCK_STREAM, 0);
116 if (socket == -1)
117 return false;
118
119 sockaddr_in serv_addr;
120 serv_addr.sin_family = AF_INET;
121 serv_addr.sin_port = htons(short(distantPort));
122 if (inet_pton(AF_INET, distantAddress.c_str(), &serv_addr.sin_addr) <= 0) {
123 printf("incorrect network address.");
124 close(socket);
125 return false;
126 }
127 memset(&(serv_addr.sin_zero), '\0', 8);
128
129 // go non blocking
130 int flags = fcntl(socket, F_GETFL);
131 fcntl(socket, F_SETFL, flags | O_NONBLOCK);
132 if (connect(socket, (sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
133 if ((errno != EINPROGRESS) && (errno != EAGAIN)) {
134 char errorMsg[256];
135 Err("socket connect: %s\n",
136 strerror_r(errno, errorMsg, sizeof(errorMsg)));
137 success = false;
138 } else {
139 // now block with a timeout
140 struct timeval tv;
141 if (timeout != 0) {// timeout is in ns
142 tv.tv_sec = timeout /((Time)1000000000);
143 tv.tv_usec = (timeout%((Time)1000000000))/1000;
144 Printf("%i %i\n",tv.tv_sec,tv.tv_usec);
145 }
146 fd_set wset;
147 FD_ZERO(&wset);
148 FD_SET(socket, &wset);
149 int ret =
150 select(socket + 1, NULL, &wset, NULL,
151 (timeout == 0) ? NULL : &tv); // man 2 connect EINPROGRESS
152 if (ret < 0) {
153 char errorMsg[256];
154 Err("select: %s\n", strerror_r(errno, errorMsg, sizeof(errorMsg)));
155 success = false;
156 } else {
157 if (ret == 0) {
158 // timeout reached
159 // Err("timeout reached\n");
160 success = false;
161 } else {
162 // something happened on our socket. Check if an error occured
163 int error;
164 socklen_t len = sizeof(error);
165 if (getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, &len) != 0) {
166 //char errorMsg[256];
167 // Err("getsockopt: %s\n",strerror_r(errno,errorMsg,sizeof(errorMsg)));
168 success = false;
169 } else if (error != 0) {
170 //char errorMsg[256];
171 // Err("socket error: %d(%s)\n",error,strerror_r(error,errorMsg,sizeof(errorMsg)));
172 success = false;
173 } else {
174 if (connect(socket, (sockaddr *)&serv_addr, sizeof(serv_addr)) ==
175 -1) {
176 success = false;
177 } else {
178 // Info("connected indeed ^^\n");
179 success = true;
180 }
181 }
182 }
183 }
184 }
185 } else {
186 success = true; // never reached suprisingly...
187 }
188 // switch back to blocking mode (default)
189 fcntl(socket, F_SETFL, flags);
190
191 if (!success) {
192 close(socket);
193 //Info("Debug: Connect to %s:%d failed\n", distantAddress.c_str(), distantPort);
194 return false;
195 } else {
196 isConnected = true;
197 this->distantPort = distantPort;
198 this->distantAddress = distantAddress;
199 //Info("Debug: Connect to %s:%d succeeded\n", distantAddress.c_str(), distantPort);
200 return true;
201 }
202}
203
204ssize_t TcpSocket::SendMessage(const char *buffer, size_t bufferSize,
205 Time timeout) {
206 int flags = 0;
207 if (!blockOnSend) {
208 flags |= MSG_DONTWAIT;
209 } else {
210 struct timeval tv;
211 tv.tv_sec = timeout / 1000; // timeout is in ms
212 tv.tv_usec = (timeout % 1000) * 1000;
213
214 setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,
215 sizeof(struct timeval));
216 }
217 ssize_t bytesSent = send(socket, buffer, bufferSize, flags);
218
219 return bytesSent;
220}
221
222ssize_t TcpSocket::RecvMessage(char *buffer, size_t bufferSize, Time timeout) {
223 int flags = 0;
224 if (!blockOnReceive) {
225 flags |= MSG_DONTWAIT;
226 } else {
227 struct timeval tv;
228 tv.tv_sec = timeout / 1000; // timeout is in ms
229 tv.tv_usec = (timeout % 1000) * 1000;
230
231 setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
232 sizeof(struct timeval));
233 }
234 ssize_t bytesRead = recv(socket, buffer, bufferSize, flags);
235
236 return bytesRead;
237}
238
239uint16_t TcpSocket::NetworkToHost16(uint16_t data) { return ntohs(data); }
240
241uint16_t TcpSocket::HostToNetwork16(uint16_t data) { return htons(data); }
242
243uint32_t TcpSocket::NetworkToHost32(uint32_t data) { return ntohl(data); }
244
245uint32_t TcpSocket::HostToNetwork32(uint32_t data) { return htonl(data); }
246
247} // end namespace core
248} // end namespace flair
Note: See TracBrowser for help on using the repository browser.