Belle II Software development
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
23using namespace Belle2;
24
25int TCPSocket::connect(const std::string& ip, unsigned short port)
26{
27 m_ip = ip;
28 m_port = port;
29 return connect();
30}
31
32int 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
72void 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
84size_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
107size_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
126size_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 }
141 return 0;
142}
143
144void TCPSocket::print()
145{
146 sockaddr_in sa;
147 memset(&sa, 0, sizeof(sockaddr_in));
148 socklen_t sa_len = sizeof(sa);
149 if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
150 perror("getsockname");
151 }
152 printf("Local IP address is: %s\n", inet_ntoa(sa.sin_addr));
153 printf("Local port is: %d\n", (int) ntohs(sa.sin_port));
154}
155
156const std::string TCPSocket::getLocalIP()
157{
158 sockaddr_in sa;
159 memset(&sa, 0, sizeof(sockaddr_in));
160 socklen_t sa_len = sizeof(sa);
161 if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
162 return "";
163 }
164 return inet_ntoa(sa.sin_addr);
165}
166
167int TCPSocket::getLocalAddress()
168{
169 sockaddr_in sa;
170 memset(&sa, 0, sizeof(sockaddr_in));
171 socklen_t sa_len = sizeof(sa);
172 if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
173 return 0;
174 }
175 return sa.sin_addr.s_addr;
176}
177
178int TCPSocket::getLocalPort()
179{
180 sockaddr_in sa;
181 memset(&sa, 0, sizeof(sockaddr_in));
182 socklen_t sa_len = sizeof(sa);
183 if (getsockname(m_fd, (struct sockaddr*)&sa, (socklen_t*)&sa_len) != 0) {
184 return 0;
185 }
186 return ntohs(sa.sin_port);
187}
188
189unsigned int TCPSocket::getAddress()
190{
191 struct hostent* host = NULL;
192 host = gethostbyname(m_ip.c_str());
193 if (host == NULL) {
194 unsigned long ip_address = inet_addr(m_ip.c_str());
195 if ((signed long) ip_address < 0) {
196 throw (std::exception());
197 // throw (IOException("Wrong host name or ip")); // TODO which throw is the correct one?
198 } else {
199 host = gethostbyaddr((char*)&ip_address, sizeof(ip_address), AF_INET);
200 }
201 }
202 return (*(unsigned long*) host->h_addr_list[0]);
203}
Abstract base class for different kinds of events.