Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcs/csbind.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1990-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* internet address/port binding
26
*/
27
28
#include "cslib.h"
29
30
/*
31
* low level for csbind()
32
*/
33
34
static int
35
portbind(register Cs_t* state, const char* type, unsigned long addr, unsigned int port)
36
{
37
38
#if CS_LIB_V10
39
40
int fd;
41
struct tcpuser tcp;
42
43
if (streq(type, "udp"))
44
{
45
if (!addr)
46
{
47
if ((fd = udp_datagram(port)) < 0)
48
messagef((state->id, NiL, -1, "bind: %s: udp_datagram error", type));
49
return fd;
50
}
51
if (addr == CS_LOCAL) addr = 0;
52
if ((fd = udp_connect(0, addr, port)) < 0)
53
messagef((state->id, NiL, -1, "bind: %s: udp_connect error", type));
54
return fd;
55
}
56
else if (streq(type, "tcp"))
57
{
58
if ((fd = tcp_sock()) < 0)
59
{
60
messagef((state->id, NiL, -1, "bind: %s: tcp_sock error", type));
61
return -1;
62
}
63
memzero(&tcp, sizeof(tcp));
64
tcp.fport = port;
65
if (addr != CS_LOCAL) tcp.faddr = addr;
66
if (addr ? !tcp_connect(fd, &tcp) : !tcp_listen(fd, &tcp))
67
{
68
state->addr = tcp.laddr;
69
state->port = tcp.lport;
70
return fd;
71
}
72
messagef((state->id, NiL, -1, "bind: %s %s error", type, addr ? "tcp_connect" : "tcp_listen"));
73
close(fd);
74
}
75
76
#else
77
78
#if CS_LIB_SOCKET
79
80
int fd;
81
int sock;
82
int r;
83
struct sockaddr_in nam;
84
Sock_size_t namlen = sizeof(nam);
85
86
if (streq(type, "tcp")) sock = SOCK_STREAM;
87
else if (streq(type, "udp")) sock = SOCK_DGRAM;
88
else
89
{
90
messagef((state->id, NiL, -1, "bind: %s: invalid type", type));
91
return -1;
92
}
93
if ((fd = socket(AF_INET, sock, 0)) < 0)
94
{
95
messagef((state->id, NiL, -1, "bind: %s: AF_INET socket error", type));
96
return -1;
97
}
98
memzero(&nam, sizeof(nam));
99
nam.sin_family = AF_INET;
100
if (addr != CS_LOCAL) nam.sin_addr.s_addr = addr;
101
state->addr = addr;
102
state->port = port;
103
nam.sin_port = htons(port);
104
if (addr)
105
{
106
#if defined(O_NONBLOCK) || defined(FNDELAY)
107
int fl;
108
#endif
109
#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
110
int sl;
111
#endif
112
if (state->flags & CS_ADDR_NOW)
113
{
114
#if defined(O_NONBLOCK) || defined(FNDELAY)
115
if ((fl = fcntl(fd, F_GETFL, 0)) != -1)
116
#if defined(FNDELAY)
117
fcntl(fd, F_SETFL, fl|FNDELAY);
118
#else
119
fcntl(fd, F_SETFL, fl|O_NONBLOCK);
120
#endif
121
#endif
122
#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
123
if (sock == SOCK_STREAM)
124
{
125
sl = 1;
126
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&sl, sizeof(sl));
127
}
128
#endif
129
}
130
if (!(r = connect(fd, (struct sockaddr*)&nam, sizeof(nam)))
131
#ifdef EINPROGRESS
132
|| errno == EINPROGRESS
133
#endif
134
)
135
{
136
if (!r && (state->flags & CS_ADDR_NOW))
137
{
138
#if defined(O_NONBLOCK) || defined(FNDELAY)
139
if (fl != -1)
140
fcntl(fd, F_SETFL, fl);
141
#endif
142
#if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
143
if (sock == SOCK_STREAM)
144
{
145
sl = 0;
146
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&sl, sizeof(sl));
147
}
148
#endif
149
}
150
state->addr = nam.sin_addr.s_addr;
151
state->port = port;
152
return fd;
153
}
154
messagef((state->id, NiL, -1, "bind: %s: connect error", type));
155
if (errno == EADDRNOTAVAIL || errno == ECONNREFUSED)
156
errno = ENOENT;
157
}
158
else
159
{
160
#ifdef SO_REUSEADDR
161
if (state->port != CS_PORT_NORMAL)
162
{
163
int n = 1;
164
165
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&n, sizeof(n));
166
}
167
#endif
168
if (!bind(fd, (struct sockaddr*)&nam, sizeof(nam)) && (sock != SOCK_STREAM || !listen(fd, 32)))
169
{
170
if (!getsockname(fd, (struct sockaddr*)&nam, &namlen) && namlen == sizeof(nam))
171
{
172
state->addr = nam.sin_addr.s_addr;
173
state->port = ntohs((unsigned short)nam.sin_port);
174
}
175
else messagef((state->id, NiL, -1, "bind: %s: getsockname error", type));
176
return fd;
177
}
178
messagef((state->id, NiL, -1, "bind: %s: bind error", type));
179
if (errno == EADDRINUSE) errno = EEXIST;
180
}
181
close(fd);
182
183
#else
184
185
errno = ENOTDIR;
186
messagef((state->id, NiL, -1, "bind: %s: not supported", type));
187
188
#endif
189
190
#endif
191
192
return -1;
193
}
194
195
/*
196
* create [addr==0] or open stream fd for <type,addr,port>
197
* for create
198
*
199
* addr CS_LOCAL for local address
200
*
201
* port CS_PORT_NORMAL for normal port allocation
202
* CS_PORT_RESERVED for reserved port allocation
203
*/
204
205
int
206
csbind(register Cs_t* state, const char* type, unsigned long addr, unsigned long port, unsigned long clone)
207
{
208
int fd;
209
210
messagef((state->id, NiL, -8, "bind(%s,%s,%u,%lu) call", type, csntoa(state, addr), port, clone));
211
if (port == CS_PORT_INVALID)
212
return -1;
213
if (port == CS_PORT_RESERVED)
214
{
215
static unsigned int last = IPPORT_RESERVED;
216
217
if (addr)
218
{
219
errno = EROFS;
220
messagef((state->id, NiL, -1, "bind: %s: explicit reserved port invalid", csntoa(state, addr)));
221
return -1;
222
}
223
port = last;
224
do
225
{
226
if (--last <= IPPORT_RESERVED / 2)
227
port = IPPORT_RESERVED - 1;
228
if (last == port)
229
{
230
errno = ENOSPC;
231
messagef((state->id, NiL, -1, "bind: no more reserved ports"));
232
break;
233
}
234
if ((fd = portbind(state, type, 0L, last)) >= 0)
235
goto ok;
236
} while (errno != EACCES);
237
messagef((state->id, NiL, -1, "bind: reserved port allocation error"));
238
return -1;
239
}
240
if (port == CS_PORT_NORMAL && addr)
241
{
242
errno = EROFS;
243
return -1;
244
}
245
if ((fd = portbind(state, type, addr, port)) < 0)
246
return -1;
247
if (clone)
248
{
249
int n;
250
char buf[16];
251
252
n = sfsprintf(buf, sizeof(buf), "%d %lu\n", CS_KEY_CLONE, clone);
253
cswrite(state, fd, buf, n);
254
}
255
ok:
256
messagef((state->id, NiL, -8, "bind(%s,%s,%u,%lu) = %d", type, csntoa(state, addr), port, clone, fd));
257
return fd;
258
}
259
260
int
261
_cs_bind(const char* type, unsigned long addr, unsigned long port, unsigned long clone)
262
{
263
return csbind(&cs, type, addr, port, clone);
264
}
265
266