Belle II Software  release-08-01-10
TCPServerSocket.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/TCPServerSocket.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 #include <errno.h>
18 
19 #include <netinet/in.h>
20 #include <netdb.h>
21 
22 using namespace Belle2;
23 
24 int TCPServerSocket::open(const std::string& ip, unsigned short port,
25  int nqueue)
26 {
27  m_ip = ip;
28  m_port = port;
29  return open(nqueue);
30 }
31 
32 int TCPServerSocket::open(int nqueue)
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  m_fd = socket(PF_INET, SOCK_STREAM, 0);
44  if (m_fd == -1) {
45  m_fd = 0;
46  throw (IOException("Fail to create a server socket."));
47  }
48  int enable = 1;
49  if (setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
50  m_fd = 0;
51  throw (IOException("Fail to set resue address for the socket."));
52  }
53  struct hostent* host = NULL;
54  host = gethostbyname(m_ip.c_str());
55  if (host == NULL) {
56  unsigned long ip_address = inet_addr(m_ip.c_str());
57  if ((signed long) ip_address < 0) {
58  throw (std::exception());
59  throw (IOException("Wrong host name or ip"));
60  } else {
61  host = gethostbyaddr((char*)&ip_address, sizeof(ip_address), AF_INET);
62  }
63  }
64  if (host == NULL) {
65  throw (IOException("Fail to get host ip: %s", m_ip.c_str()));
66  }
67  addr.sin_addr.s_addr = (*(unsigned long*)host->h_addr_list[0]);
68 
69  if (bind(m_fd, (const sockaddr*) & (addr), sizeof(sockaddr_in)) != 0) {
70  throw (IOException("Fail to bind the socket. %s:%d", m_ip.c_str(), m_port));
71  }
72  if (listen(m_fd, nqueue) != 0) {
73  throw (IOException("Fail to listen to the socket."));
74  }
75  return m_fd;
76 }
77 
78 TCPSocket TCPServerSocket::accept()
79 {
80  socklen_t len = sizeof(sockaddr_in);
81  sockaddr_in addr;
82  memset(&addr, 0, sizeof(sockaddr_in));
83  addr.sin_family = AF_INET;
84  addr.sin_addr.s_addr = INADDR_ANY;
85  addr.sin_port = htons(m_port);
86  int fd;
87  errno = 0;
88  while (true) {
89  if ((fd = ::accept(m_fd, (sockaddr*) & (addr), &len)) == -1) {
90  switch (errno) {
91  case EINTR: continue;
92  case EAGAIN: continue;
93  default:
94  perror("accept");
95  throw (IOException("Fail to accept."));
96  }
97  }
98  break;
99  }
100  TCPSocket s(fd);
101  s.m_ip = inet_ntoa(addr.sin_addr);
102  s.m_port = ntohs(addr.sin_port);
103  return s;
104 }
Abstract base class for different kinds of events.