Belle II Software  release-08-01-10
TCPSocket.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include "daq/slc/system/TCPSocket.h"
9 
10 #include <daq/slc/base/IOException.h>
11 
12 #include <cstdio>
13 #include <cstring>
14 
15 #include <sys/socket.h>
16 #include <arpa/inet.h>
17 
18 #include <unistd.h>
19 #include <netinet/in.h>
20 #include <errno.h>
21 #include <netdb.h>
22 
23 using namespace Belle2;
24 
25 int TCPSocket::connect(const std::string& ip, unsigned short port)
26 {
27  m_ip = ip;
28  m_port = port;
29  return connect();
30 }
31 
32 int TCPSocket::connect()
33 {
34  if (m_fd > 0) {
35  throw (IOException("Socket is working already."));
36  }
37  sockaddr_in addr;
38  memset(&addr, 0, sizeof(sockaddr_in));
39  addr.sin_family = AF_INET;
40  addr.sin_addr.s_addr = INADDR_ANY;
41  addr.sin_port = htons(m_port);
42 
43  if ((m_fd = ::socket(PF_INET, SOCK_STREAM, 0)) < 0) {
44  throw (IOException("Failed to create socket"));
45  }
46  struct hostent* host = NULL;
47  host = gethostbyname(m_ip.c_str());
48  if (host == NULL) {
49  unsigned long ip_address = inet_addr(m_ip.c_str());
50  if ((signed long) ip_address < 0) {
51  throw (IOException("Wrong host name or ip"));
52  } else {
53  host = gethostbyaddr((char*)&ip_address, sizeof(ip_address), AF_INET);
54  }
55  }
56  if (host == NULL) {
57  close();
58  throw (IOException("Failed to connect host %s:%d",
59  m_ip.c_str(), m_port));
60  }
61  addr.sin_addr.s_addr = (*(unsigned long*) host->h_addr_list[0]);
62 
63  if (::connect(m_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
64  close();
65  throw (IOException("Failed to connect host %s:%d",
66  m_ip.c_str(), m_port));
67  }
68 
69  return m_fd;
70 }
71 
72 void TCPSocket::setBufferSize(int size)
73 {
74  if (size > 0) {
75  if (setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) != 0) {
76  throw (IOException("failed to SO_SNDBUF: %s\n", strerror(errno)));
77  }
78  if (setsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) != 0) {
79  throw (IOException("error on SO_RCVBUF: %s\n", strerror(errno)));
80  }
81  }
82 }
83 
84 size_t TCPSocket::write(const void* buf, size_t count)
85 {
86  size_t c = 0;
87  while (c < count) {
88  errno = 0;
89  int ret = send(m_fd, ((unsigned char*)buf + c), (count - c), MSG_NOSIGNAL);
90  if (ret <= 0) {
91  switch (errno) {
92  case EINTR: continue;
93  case ENETUNREACH:
94  case EHOSTUNREACH:
95  case ETIMEDOUT:
96  usleep(500);
97  continue;
98  default:
99  throw (IOException("Error while writing"));
100  }
101  }
102  c += ret;
103  }
104  return c;
105 }
106 
107 size_t TCPSocket::read(void* buf, size_t count)
108 {
109  size_t c = 0;
110  while (c < count) {
111  errno = 0;
112  int ret = recv(m_fd, ((unsigned char*)buf + c), (count - c), 0);
113  if (ret <= 0) {
114  switch (errno) {
115  case EINTR: continue;
116  case EAGAIN: continue;
117  default:
118  throw (IOException("TCPSocket::read Error while reading."));
119  }
120  }
121  c += ret;
122  }
123  return c;
124 }
125 
126 size_t TCPSocket::read_once(void* buf, size_t count)
127 {
128  errno = 0;
129  while (true) {
130  int ret = recv(m_fd, buf, count, 0);
131  if (ret <= 0) {
132  switch (errno) {
133  case EINTR: continue;
134  case EAGAIN: continue;
135  default:
136  throw (IOException("TCPSocket::read_once Error while reading."));
137  }
138  }
139  return ret;
140  break;
141  }
142  return 0;
143 }
144 
145 void TCPSocket::print()
146 {
147  sockaddr_in sa;
148  memset(&sa, 0, sizeof(sockaddr_in));
149  socklen_t sa_len = sizeof(sa);
150  if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
151  perror("getsockname");
152  }
153  printf("Local IP address is: %s\n", inet_ntoa(sa.sin_addr));
154  printf("Local port is: %d\n", (int) ntohs(sa.sin_port));
155 }
156 
157 const std::string TCPSocket::getLocalIP()
158 {
159  sockaddr_in sa;
160  memset(&sa, 0, sizeof(sockaddr_in));
161  socklen_t sa_len = sizeof(sa);
162  if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
163  return "";
164  }
165  return inet_ntoa(sa.sin_addr);
166 }
167 
168 int TCPSocket::getLocalAddress()
169 {
170  sockaddr_in sa;
171  memset(&sa, 0, sizeof(sockaddr_in));
172  socklen_t sa_len = sizeof(sa);
173  if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
174  return 0;
175  }
176  return sa.sin_addr.s_addr;
177 }
178 
179 int TCPSocket::getLocalPort()
180 {
181  sockaddr_in sa;
182  memset(&sa, 0, sizeof(sockaddr_in));
183  socklen_t sa_len = sizeof(sa);
184  if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
185  return 0;
186  }
187  return ntohs(sa.sin_port);
188 }
189 
190 unsigned int TCPSocket::getAddress()
191 {
192  struct hostent* host = NULL;
193  host = gethostbyname(m_ip.c_str());
194  if (host == NULL) {
195  unsigned long ip_address = inet_addr(m_ip.c_str());
196  if ((signed long) ip_address < 0) {
197  throw (std::exception());
198  throw (IOException("Wrong host name or ip"));
199  } else {
200  host = gethostbyaddr((char*)&ip_address, sizeof(ip_address), AF_INET);
201  }
202  }
203  return (*(unsigned long*) host->h_addr_list[0]);
204 }
Abstract base class for different kinds of events.