Belle II Software development
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
22using namespace Belle2;
23
24int 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
32int 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")); // TODO which throw is the correct one?
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
78TCPSocket 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.