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

Last change on this file since 217 was 213, checked in by Sanahuja Guillaume, 6 years ago

thread stack size rework
add Matrix class

File size: 7.2 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) {
142 tv.tv_sec = timeout / 1000; // timeout is in ms
143 tv.tv_usec = (timeout % 1000) * 1000;
144 }
145 fd_set wset;
146 FD_ZERO(&wset);
147 FD_SET(socket, &wset);
148 int ret =
149 select(socket + 1, NULL, &wset, NULL,
150 (timeout == 0) ? NULL : &tv); // man 2 connect EINPROGRESS
151 if (ret < 0) {
152 char errorMsg[256];
153 Err("select: %s\n", strerror_r(errno, errorMsg, sizeof(errorMsg)));
154 success = false;
155 } else {
156 if (ret == 0) {
157 // timeout reached
158 // Err("timeout reached\n");
159 success = false;
160 } else {
161 // something happened on our socket. Check if an error occured
162 int error;
163 socklen_t len = sizeof(error);
164 if (getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, &len) != 0) {
165 //char errorMsg[256];
166 // Err("getsockopt: %s\n",strerror_r(errno,errorMsg,sizeof(errorMsg)));
167 success = false;
168 } else if (error != 0) {
169 //char errorMsg[256];
170 // Err("socket error: %d(%s)\n",error,strerror_r(error,errorMsg,sizeof(errorMsg)));
171 success = false;
172 } else {
173 if (connect(socket, (sockaddr *)&serv_addr, sizeof(serv_addr)) ==
174 -1) {
175 success = false;
176 } else {
177 // Info("connected indeed ^^\n");
178 success = true;
179 }
180 }
181 }
182 }
183 }
184 } else {
185 success = true; // never reached suprisingly...
186 }
187 // switch back to blocking mode (default)
188 fcntl(socket, F_SETFL, flags);
189
190 if (!success) {
191 close(socket);
192 // Info("Debug: Connect to %s:%d failed\n", distantAddress.c_str(),
193 // 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(),
200 // distantPort);
201 return true;
202 }
203}
204
205ssize_t TcpSocket::SendMessage(const char *buffer, size_t bufferSize,
206 Time timeout) {
207 int flags = 0;
208 if (!blockOnSend) {
209 flags |= MSG_DONTWAIT;
210 } else {
211 struct timeval tv;
212 tv.tv_sec = timeout / 1000; // timeout is in ms
213 tv.tv_usec = (timeout % 1000) * 1000;
214
215 setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,
216 sizeof(struct timeval));
217 }
218 ssize_t bytesSent = send(socket, buffer, bufferSize, flags);
219
220 return bytesSent;
221}
222
223ssize_t TcpSocket::RecvMessage(char *buffer, size_t bufferSize, Time timeout) {
224 int flags = 0;
225 if (!blockOnReceive) {
226 flags |= MSG_DONTWAIT;
227 } else {
228 struct timeval tv;
229 tv.tv_sec = timeout / 1000; // timeout is in ms
230 tv.tv_usec = (timeout % 1000) * 1000;
231
232 setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
233 sizeof(struct timeval));
234 }
235 ssize_t bytesRead = recv(socket, buffer, bufferSize, flags);
236
237 return bytesRead;
238}
239
240uint16_t TcpSocket::NetworkToHost16(uint16_t data) { return ntohs(data); }
241
242uint16_t TcpSocket::HostToNetwork16(uint16_t data) { return htons(data); }
243
244uint32_t TcpSocket::NetworkToHost32(uint32_t data) { return ntohl(data); }
245
246uint32_t TcpSocket::HostToNetwork32(uint32_t data) { return htonl(data); }
247
248} // end namespace core
249} // end namespace flair
Note: See TracBrowser for help on using the repository browser.