1/*************************************************************************
2 * libjson-rpc-cpp
3 *************************************************************************
4 * @file linuxtcpsocketserver.cpp
5 * @date 17.07.2015
6 * @author Alexandre Poirot <alexandre.poirot@legrand.fr>
7 * @license See attached LICENSE.txt
8 ************************************************************************/
9
10#include "linuxtcpsocketserver.h"
11#include "../../common/sharedconstants.h"
12#include "../../common/streamreader.h"
13#include "../../common/streamwriter.h"
14#include <cstdio>
15#include <cstdlib>
16#include <cstring>
17#include <fcntl.h>
18#include <sys/types.h>
19#include <unistd.h>
20
21#include <errno.h>
22#include <iostream>
23#include <sstream>
24#include <string>
25
26using namespace jsonrpc;
27using namespace std;
28
29LinuxTcpSocketServer::LinuxTcpSocketServer(const std::string &ipToBind, const unsigned int &port, size_t threads)
30 : AbstractThreadedServer(threads), ipToBind(ipToBind), port(port) {}
31
32LinuxTcpSocketServer::~LinuxTcpSocketServer() {
33 shutdown(this->socket_fd, 2);
34 close(this->socket_fd);
35}
36
37bool LinuxTcpSocketServer::InitializeListener() {
38 this->socket_fd = socket(AF_INET, SOCK_STREAM, 0);
39 if (this->socket_fd < 0) {
40 return false;
41 }
42
43 fcntl(this->socket_fd, F_SETFL, FNDELAY);
44 int reuseaddr = 1;
45 setsockopt(this->socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
46
47 /* start with a clean address structure */
48 memset(&(this->address), 0, sizeof(struct sockaddr_in));
49
50 this->address.sin_family = AF_INET;
51 inet_aton(this->ipToBind.c_str(), &(this->address.sin_addr));
52 this->address.sin_port = htons(this->port);
53
54 if (::bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_in)) != 0) {
55 return false;
56 }
57
58 if (listen(this->socket_fd, 5) != 0) {
59 return false;
60 }
61 return true;
62}
63
64int LinuxTcpSocketServer::CheckForConnection() {
65 struct sockaddr_in connection_address;
66 memset(&connection_address, 0, sizeof(struct sockaddr_in));
67 socklen_t address_length = sizeof(connection_address);
68 return accept(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(connection_address)), &address_length);
69}
70
71void LinuxTcpSocketServer::HandleConnection(int connection) {
72 StreamReader reader(DEFAULT_BUFFER_SIZE);
73 string request, response;
74
75 reader.Read(request, connection, DEFAULT_DELIMITER_CHAR);
76
77 this->ProcessRequest(request, response);
78
79 response.append(1, DEFAULT_DELIMITER_CHAR);
80 StreamWriter writer;
81 writer.Write(response, connection);
82 CleanClose(connection);
83}
84
85bool LinuxTcpSocketServer::WaitClientClose(const int &fd, const int &timeout) {
86 bool ret = false;
87 int i = 0;
88 while ((recv(fd, NULL, 0, 0) != 0) && i < timeout) {
89 usleep(1);
90 ++i;
91 ret = true;
92 }
93
94 return ret;
95}
96
97int LinuxTcpSocketServer::CloseByReset(const int &fd) {
98 struct linger so_linger;
99 so_linger.l_onoff = 1;
100 so_linger.l_linger = 0;
101
102 int ret = setsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
103 if (ret != 0)
104 return ret;
105
106 return close(fd);
107}
108
109int LinuxTcpSocketServer::CleanClose(const int &fd) {
110 if (WaitClientClose(fd)) {
111 return close(fd);
112 } else {
113 return CloseByReset(fd);
114 }
115}
116