Belle II Software  release-06-01-15
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  int ret;
88  while (c < count) {
89  errno = 0;
90  ret = send(m_fd, ((unsigned char*)buf + c), (count - c), MSG_NOSIGNAL);
91  if (ret <= 0) {
92  switch (errno) {
93  case EINTR: continue;
94  case ENETUNREACH:
95  case EHOSTUNREACH:
96  case ETIMEDOUT:
97  usleep(500);
98  continue;
99  default:
100  throw (IOException("Error while writing"));
101  }
102  }
103  c += ret;
104  }
105  return c;
106 }
107 
108 size_t TCPSocket::read(void* buf, size_t count)
109 {
110  size_t c = 0;
111  int ret;
112  while (c < count) {
113  errno = 0;
114  ret = recv(m_fd, ((unsigned char*)buf + c), (count - c), 0);
115  if (ret <= 0) {
116  switch (errno) {
117  case EINTR: continue;
118  case EAGAIN: continue;
119  default:
120  throw (IOException("TCPSocket::read Error while reading."));
121  }
122  }
123  c += ret;
124  }
125  return c;
126 }
127 
128 size_t TCPSocket::read_once(void* buf, size_t count)
129 {
130  int ret;
131  errno = 0;
132  while (true) {
133  ret = recv(m_fd, buf, count, 0);
134  if (ret <= 0) {
135  switch (errno) {
136  case EINTR: continue;
137  case EAGAIN: continue;
138  default:
139  throw (IOException("TCPSocket::read_once Error while reading."));
140  }
141  }
142  break;
143  }
144  return ret;
145 }
146 
147 void TCPSocket::print()
148 {
149  sockaddr_in sa;
150  memset(&sa, 0, sizeof(sockaddr_in));
151  socklen_t sa_len = sizeof(sa);
152  if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
153  perror("getsockname");
154  }
155  printf("Local IP address is: %s\n", inet_ntoa(sa.sin_addr));
156  printf("Local port is: %d\n", (int) ntohs(sa.sin_port));
157 }
158 
159 const std::string TCPSocket::getLocalIP()
160 {
161  sockaddr_in sa;
162  memset(&sa, 0, sizeof(sockaddr_in));
163  socklen_t sa_len = sizeof(sa);
164  if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
165  return "";
166  }
167  return inet_ntoa(sa.sin_addr);
168 }
169 
170 int TCPSocket::getLocalAddress()
171 {
172  sockaddr_in sa;
173  memset(&sa, 0, sizeof(sockaddr_in));
174  socklen_t sa_len = sizeof(sa);
175  if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
176  return 0;
177  }
178  return sa.sin_addr.s_addr;
179 }
180 
181 int TCPSocket::getLocalPort()
182 {
183  sockaddr_in sa;
184  memset(&sa, 0, sizeof(sockaddr_in));
185  socklen_t sa_len = sizeof(sa);
186  if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
187  return 0;
188  }
189  return ntohs(sa.sin_port);
190 }
191 
192 unsigned int TCPSocket::getAddress()
193 {
194  struct hostent* host = NULL;
195  host = gethostbyname(m_ip.c_str());
196  if (host == NULL) {
197  unsigned long ip_address = inet_addr(m_ip.c_str());
198  if ((signed long) ip_address < 0) {
199  throw (std::exception());
200  throw (IOException("Wrong host name or ip"));
201  } else {
202  host = gethostbyaddr((char*)&ip_address, sizeof(ip_address), AF_INET);
203  }
204  }
205  return (*(unsigned long*) host->h_addr_list[0]);
206 }
Abstract base class for different kinds of events.