-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstream_server.cpp
179 lines (154 loc) · 4.93 KB
/
stream_server.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//=============================================================================
// File: stream_server.hpp
// Description: Class abstracting a socket server
// Author: Marcelo Arroyo
// Copyright: LGPL
// Changes:
//=============================================================================
#include <unistd.h> // for read(), write(), close(), ...
#include <stdlib.h>
#include <string.h> // for strlen
#include <string> // for string
#include <sys/socket.h> // for socket(), connect(), ...
#include <arpa/inet.h> // for struct inet_addr
#include <netdb.h> // for hostent (DNS search service)
#include <algorithm> // for std::max
#include <iostream>
#include "stream_server.hpp"
#ifdef UNIX
static int interrupted = 0;
static void signal_handler (int signal_value)
{
interrupted = 1;
}
static void catch_signals (void)
{
struct sigaction action;
action.sa_handler = signal_handler;
action.sa_flags = 0;
sigemptyset (&action.sa_mask);
sigaction (SIGINT, &action, NULL);
sigaction (SIGTERM, &action, NULL);
}
#endif
//=======================================================================================
// peer_connection implementation
//=======================================================================================
peer_connection & peer_connection::operator=(peer_connection & other)
{
s = other.get_socket();
peer_node = other.get_peer_node();
peer_port = other.get_peer_port();
return *this;
}
int peer_connection::send(char data[], int count)
{
return write(s, data, count);
}
int peer_connection::send(std::vector<unsigned char> data)
{
return write(s, data.data(), data.size());
}
int peer_connection::send(std::string data)
{
return write(s, data.c_str(), data.size());
}
int peer_connection::receive(char *data, int count)
{
return read(s, data, count);
}
std::vector<unsigned char> peer_connection::receive(int max_length)
{
std::vector<unsigned char> buf(max_length);
int n = read(s, &(buf[0]), max_length);
buf.resize(n);
return buf;
}
std::string peer_connection::receive_string(int max_length)
{
int size = std::max(max_length, 65000);
char buf[size];
int n = read(s, buf, size);
return std::string(buf, std::max(n,0));
}
//=======================================================================================
// stream_server implementation
//=======================================================================================
bool stream_server::bind_to(sa_family_t family, std::string node, std::string service)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = 0;
hints.ai_addr = 0;
hints.ai_next = 0;
if (getaddrinfo(node.c_str(), service.c_str(), &hints, &result) != 0)
return false;
if (s !=- 1) close(s);
for (rp = result; rp != 0; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s == -1)
continue;
if (bind(s, rp->ai_addr, rp->ai_addrlen) == 0) {
char node_buf[NI_MAXHOST];
char service_buf[NI_MAXSERV];
getnameinfo(rp->ai_addr, rp->ai_addrlen, node_buf, NI_MAXHOST,
service_buf, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
this->node = node_buf; this->service = service_buf;
binded = true;
break; // success
}
close(s);
}
freeaddrinfo(result);
if ( listen(s,5) == -1 ) {
close(s);
binded = false;
std::cerr << "Listen error..." << std::endl;
}
return binded;
}
peer_connection stream_server::accept_connection()
{
struct sockaddr_storage peer;
socklen_t peer_length = sizeof(peer);
char host[NI_MAXHOST], service[NI_MAXSERV];
host[0] = service[0] = 0;
int cs = accept(s, (struct sockaddr *) & peer, &peer_length);
if ( cs != -1 )
getnameinfo((struct sockaddr *) &peer, peer_length, host, NI_MAXHOST,
service, NI_MAXSERV, NI_NUMERICSERV);
return peer_connection(cs, host, service);
}
void stream_server::run()
{
#ifdef UNIX
catch_signals();
#endif
while(true) {
if (interrupted) {
std::cout << "Interrupted..." << std::endl;
break;
}
peer_connection conn = accept_connection();
if (interrupted) {
std::cout << "Interrupted..." << std::endl;
break;
}
service_fn(conn);
}
disconnect();
}
// Default service function
void stream_server::service_fn(peer_connection & conn)
{
std::cout << "Connected with" << conn.get_peer_node() << ':'
<< conn.get_peer_port() << std::endl;
std::string s = conn.receive_string();
std::cout << "Received from client:" << s << std::endl;
conn.send("OK");
}