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

Last change on this file since 2 was 2, checked in by Sanahuja Guillaume, 7 years ago

flaircore

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