forked from ahupowerdns/metronome
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathiputils.cc
173 lines (148 loc) · 4.24 KB
/
iputils.cc
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
#include "iputils.hh"
/** these functions provide a very lightweight wrapper to the Berkeley sockets API. Errors -> exceptions! */
using namespace std;
static void RuntimeError(const boost::format& fmt)
{
throw runtime_error(fmt.str());
}
int SSocket(int family, int type, int flags)
{
int ret = socket(family, type, flags);
if(ret < 0)
RuntimeError(boost::format("creating socket of type %d: %s") % family % strerror(errno));
return ret;
}
int SConnect(int sockfd, const ComboAddress& remote)
{
int ret = connect(sockfd, (struct sockaddr*)&remote, remote.getSocklen());
if(ret < 0)
RuntimeError(boost::format("connecting socket to %s: %s") % remote.toStringWithPort() % strerror(errno));
return ret;
}
int SBind(int sockfd, const ComboAddress& local)
{
int ret = ::bind(sockfd, (struct sockaddr*)&local, local.getSocklen());
if(ret < 0)
RuntimeError(boost::format("binding socket to %s: %s") % local.toStringWithPort() % strerror(errno));
return ret;
}
int SAccept(int sockfd, ComboAddress& remote)
{
socklen_t remlen = remote.getSocklen();
int ret = accept(sockfd, (struct sockaddr*)&remote, &remlen);
if(ret < 0)
RuntimeError(boost::format("accepting new connection on socket: %s") % strerror(errno));
return ret;
}
int SListen(int sockfd, int limit)
{
int ret = listen(sockfd, limit);
if(ret < 0)
RuntimeError(boost::format("setting socket to listen: %s") % strerror(errno));
return ret;
}
int SSetsockopt(int sockfd, int level, int opname, int value)
{
int ret = setsockopt(sockfd, level, opname, &value, sizeof(value));
if(ret < 0)
RuntimeError(boost::format("setsockopt for level %d and opname %d to %d failed: %s") % level % opname % value % strerror(errno));
return ret;
}
int writen(int fd, const void *buf, size_t count)
{
const char *ptr = (char*)buf;
const char *eptr = ptr + count;
int res;
while(ptr != eptr) {
res = ::write(fd, ptr, eptr - ptr);
if(res < 0) {
if (errno == EAGAIN)
throw std::runtime_error("used writen on non-blocking socket, got EAGAIN");
else
unixDie("failed in writen");
}
else if (res == 0)
throw std::runtime_error("could not write all bytes, got eof in writen2");
ptr += res;
}
return count;
}
int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret)
{
if(addr.empty())
return -1;
string ourAddr(addr);
int port = -1;
if(addr[0]=='[') { // [::]:53 style address
string::size_type pos = addr.find(']');
if(pos == string::npos || pos + 2 > addr.size() || addr[pos+1]!=':')
return -1;
ourAddr.assign(addr.c_str() + 1, pos-1);
port = atoi(addr.c_str()+pos+2);
}
struct addrinfo* res;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_flags = AI_NUMERICHOST;
int error;
if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { // this is correct
/*
cerr<<"Error translating IPv6 address '"<<addr<<"': ";
if(error==EAI_SYSTEM)
cerr<<strerror(errno)<<endl;
else
cerr<<gai_strerror(error)<<endl;
*/
return -1;
}
memcpy(ret, res->ai_addr, res->ai_addrlen);
if(port >= 0)
ret->sin6_port = htons(port);
freeaddrinfo(res);
return 0;
}
int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret)
{
if(str.empty()) {
return -1;
}
struct in_addr inp;
string::size_type pos = str.find(':');
if(pos == string::npos) { // no port specified, not touching the port
if(inet_aton(str.c_str(), &inp)) {
ret->sin_addr.s_addr=inp.s_addr;
return 0;
}
return -1;
}
if(!*(str.c_str() + pos + 1)) // trailing :
return -1;
char *eptr = (char*)str.c_str() + str.size();
int port = strtol(str.c_str() + pos + 1, &eptr, 10);
if(*eptr)
return -1;
ret->sin_port = htons(port);
if(inet_aton(str.substr(0, pos).c_str(), &inp)) {
ret->sin_addr.s_addr=inp.s_addr;
return 0;
}
return -1;
}
bool sockGetLine(int sock, string* ret)
{
ret->clear();
char c;
int err;
for(;;) {
err=read(sock, &c, 1);
if(err < 0)
throw runtime_error("Error reading from socket: "+string(strerror(errno)));
if(!err)
break;
ret->append(1, c);
if(c=='\n')
break;
}
return !ret->empty();
}