]>
Commit | Line | Data |
---|---|---|
282113ba | 1 | /* transport_sockets.cc |
f449bfef | 2 | |
1dcd520b | 3 | Copyright 2001, 2002, 2003, 2004 Red Hat Inc. |
f449bfef RC |
4 | |
5 | Written by Robert Collins <rbtcollins@hotmail.com> | |
6 | ||
1c001dd2 | 7 | This file is part of Cygwin. |
f449bfef | 8 | |
1c001dd2 CS |
9 | This software is a copyrighted work licensed under the terms of the |
10 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
11 | details. */ | |
f449bfef | 12 | |
1c001dd2 CS |
13 | /* to allow this to link into cygwin and the .dll, a little magic is needed. */ |
14 | #ifdef __OUTSIDE_CYGWIN__ | |
15 | #include "woutsup.h" | |
16 | #else | |
17 | #include "winsup.h" | |
18 | #endif | |
19 | ||
20 | #include <sys/types.h> | |
21 | #include <sys/socket.h> | |
22 | #include <sys/stat.h> | |
23 | ||
24 | #include <assert.h> | |
f449bfef RC |
25 | #include <stdio.h> |
26 | #include <unistd.h> | |
1c001dd2 | 27 | |
1dcd520b | 28 | #include "cygerrno.h" |
282113ba CV |
29 | #include "transport.h" |
30 | #include "transport_sockets.h" | |
f449bfef | 31 | |
1dcd520b CV |
32 | #ifdef __INSIDE_CYGWIN__ |
33 | #define SET_ERRNO(err) set_errno (err) | |
34 | #define GET_ERRNO() get_errno () | |
35 | #else | |
36 | #define SET_ERRNO(err) errno = (err) | |
37 | #define GET_ERRNO() (errno) | |
38 | #endif | |
39 | ||
f449bfef RC |
40 | /* to allow this to link into cygwin and the .dll, a little magic is needed. */ |
41 | #ifndef __OUTSIDE_CYGWIN__ | |
f449bfef | 42 | |
1c001dd2 CS |
43 | extern "C" int cygwin_accept (int fd, struct sockaddr *, int *len); |
44 | extern "C" int cygwin_bind (int fd, const struct sockaddr *, int len); | |
45 | extern "C" int cygwin_connect (int fd, const struct sockaddr *, int len); | |
46 | extern "C" int cygwin_listen (int fd, int backlog); | |
47 | extern "C" int cygwin_shutdown (int fd, int how); | |
48 | extern "C" int cygwin_socket (int af, int type, int protocol); | |
49 | ||
50 | #else /* __OUTSIDE_CYGWIN__ */ | |
51 | ||
52 | #define cygwin_accept(A,B,C) ::accept (A,B,C) | |
53 | #define cygwin_bind(A,B,C) ::bind (A,B,C) | |
54 | #define cygwin_connect(A,B,C) ::connect (A,B,C) | |
55 | #define cygwin_listen(A,B) ::listen (A,B) | |
56 | #define cygwin_shutdown(A,B) ::shutdown (A,B) | |
57 | #define cygwin_socket(A,B,C) ::socket (A,B,C) | |
58 | ||
59 | #endif /* __OUTSIDE_CYGWIN__ */ | |
f449bfef | 60 | |
1c001dd2 CS |
61 | enum |
62 | { | |
63 | MAX_CONNECT_RETRY = 64 | |
64 | }; | |
65 | ||
66 | transport_layer_sockets::transport_layer_sockets (const int fd) | |
67 | : _fd (fd), | |
68 | _addr_len (0), | |
69 | _is_accepted_endpoint (true), | |
70 | _is_listening_endpoint (false) | |
f449bfef | 71 | { |
1c001dd2 CS |
72 | assert (_fd != -1); |
73 | ||
74 | memset (&_addr, '\0', sizeof (_addr)); | |
75 | } | |
76 | ||
77 | transport_layer_sockets::transport_layer_sockets () | |
78 | : _fd (-1), | |
79 | _addr_len (0), | |
80 | _is_accepted_endpoint (false), | |
81 | _is_listening_endpoint (false) | |
f449bfef | 82 | { |
1c001dd2 CS |
83 | memset (&_addr, '\0', sizeof (_addr)); |
84 | ||
85 | _addr.sun_family = AF_UNIX; | |
86 | strcpy (_addr.sun_path, "/tmp/cygdaemo"); // FIXME: $TMP? | |
87 | _addr_len = SUN_LEN (&_addr); | |
f449bfef RC |
88 | } |
89 | ||
1c001dd2 CS |
90 | transport_layer_sockets::~transport_layer_sockets () |
91 | { | |
92 | close (); | |
93 | } | |
94 | ||
95 | #ifndef __INSIDE_CYGWIN__ | |
96 | ||
97 | int | |
f449bfef RC |
98 | transport_layer_sockets::listen () |
99 | { | |
1c001dd2 CS |
100 | assert (_fd == -1); |
101 | assert (!_is_accepted_endpoint); | |
102 | assert (!_is_listening_endpoint); | |
103 | ||
104 | debug_printf ("listen () [this = %p]", this); | |
105 | ||
106 | struct stat sbuf; | |
107 | ||
108 | if (stat (_addr.sun_path, &sbuf) == -1) | |
109 | { | |
1dcd520b | 110 | if (GET_ERRNO () != ENOENT) |
1c001dd2 CS |
111 | { |
112 | system_printf ("cannot access socket file `%s': %s", | |
1dcd520b | 113 | _addr.sun_path, strerror (GET_ERRNO ())); |
1c001dd2 CS |
114 | return -1; |
115 | } | |
116 | } | |
117 | else if (S_ISSOCK (sbuf.st_mode)) | |
118 | { | |
119 | // The socket already exists: is a duplicate cygserver running? | |
120 | ||
121 | const int newfd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0); | |
122 | ||
123 | if (newfd == -1) | |
124 | { | |
125 | system_printf ("failed to create UNIX domain socket: %s", | |
1dcd520b | 126 | strerror (GET_ERRNO ())); |
1c001dd2 CS |
127 | return -1; |
128 | } | |
129 | ||
130 | if (cygwin_connect (newfd, (struct sockaddr *) &_addr, _addr_len) == 0) | |
131 | { | |
132 | system_printf ("the daemon is already running"); | |
133 | (void) cygwin_shutdown (newfd, SHUT_WR); | |
134 | char buf[BUFSIZ]; | |
135 | while (::read (newfd, buf, sizeof (buf)) > 0) | |
136 | {} | |
137 | (void) ::close (newfd); | |
138 | return -1; | |
139 | } | |
140 | ||
141 | if (unlink (_addr.sun_path) == -1) | |
142 | { | |
143 | system_printf ("failed to remove `%s': %s", | |
1dcd520b | 144 | _addr.sun_path, strerror (GET_ERRNO ())); |
1c001dd2 CS |
145 | (void) ::close (newfd); |
146 | return -1; | |
147 | } | |
148 | } | |
149 | else | |
150 | { | |
151 | system_printf ("cannot create socket `%s': File already exists", | |
152 | _addr.sun_path); | |
153 | return -1; | |
154 | } | |
155 | ||
156 | _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0); | |
157 | ||
158 | if (_fd == -1) | |
159 | { | |
160 | system_printf ("failed to create UNIX domain socket: %s", | |
1dcd520b | 161 | strerror (GET_ERRNO ())); |
1c001dd2 CS |
162 | return -1; |
163 | } | |
164 | ||
165 | if (cygwin_bind (_fd, (struct sockaddr *) &_addr, _addr_len) == -1) | |
166 | { | |
1dcd520b | 167 | const int saved_errno = GET_ERRNO (); |
1c001dd2 | 168 | close (); |
1dcd520b | 169 | SET_ERRNO (saved_errno); |
1c001dd2 | 170 | system_printf ("failed to bind UNIX domain socket `%s': %s", |
1dcd520b | 171 | _addr.sun_path, strerror (GET_ERRNO ())); |
1c001dd2 CS |
172 | return -1; |
173 | } | |
174 | ||
175 | _is_listening_endpoint = true; // i.e. this really means "have bound". | |
176 | ||
177 | if (cygwin_listen (_fd, SOMAXCONN) == -1) | |
178 | { | |
1dcd520b | 179 | const int saved_errno = GET_ERRNO (); |
1c001dd2 | 180 | close (); |
1dcd520b | 181 | SET_ERRNO (saved_errno); |
1c001dd2 | 182 | system_printf ("failed to listen on UNIX domain socket `%s': %s", |
1dcd520b | 183 | _addr.sun_path, strerror (GET_ERRNO ())); |
1c001dd2 CS |
184 | return -1; |
185 | } | |
186 | ||
187 | debug_printf ("0 = listen () [this = %p, fd = %d]", this, _fd); | |
188 | ||
189 | return 0; | |
f449bfef RC |
190 | } |
191 | ||
192 | class transport_layer_sockets * | |
1c001dd2 | 193 | transport_layer_sockets::accept (bool *const recoverable) |
f449bfef | 194 | { |
1c001dd2 CS |
195 | assert (_fd != -1); |
196 | assert (!_is_accepted_endpoint); | |
197 | assert (_is_listening_endpoint); | |
198 | ||
199 | debug_printf ("accept () [this = %p, fd = %d]", this, _fd); | |
200 | ||
201 | struct sockaddr_un client_addr; | |
202 | socklen_t client_addr_len = sizeof (client_addr); | |
f449bfef | 203 | |
1c001dd2 CS |
204 | const int accept_fd = |
205 | cygwin_accept (_fd, (struct sockaddr *) &client_addr, &client_addr_len); | |
206 | ||
207 | if (accept_fd == -1) | |
f449bfef | 208 | { |
1dcd520b CV |
209 | system_printf ("failed to accept connection: %s", strerror (GET_ERRNO ())); |
210 | switch (GET_ERRNO ()) | |
1c001dd2 CS |
211 | { |
212 | case ECONNABORTED: | |
213 | case EINTR: | |
214 | case EMFILE: | |
215 | case ENFILE: | |
216 | case ENOBUFS: | |
217 | case ENOMEM: | |
218 | *recoverable = true; | |
219 | break; | |
220 | ||
221 | default: | |
222 | *recoverable = false; | |
223 | break; | |
224 | } | |
f449bfef RC |
225 | return NULL; |
226 | } | |
73ea29f4 | 227 | |
1c001dd2 | 228 | debug_printf ("%d = accept () [this = %p, fd = %d]", accept_fd, this, _fd); |
f449bfef | 229 | |
282113ba | 230 | return new transport_layer_sockets (accept_fd); |
f449bfef RC |
231 | } |
232 | ||
1c001dd2 CS |
233 | #endif /* !__INSIDE_CYGWIN__ */ |
234 | ||
f449bfef | 235 | void |
1c001dd2 | 236 | transport_layer_sockets::close () |
f449bfef | 237 | { |
1c001dd2 CS |
238 | debug_printf ("close () [this = %p, fd = %d]", this, _fd); |
239 | ||
240 | if (_is_listening_endpoint) | |
241 | (void) unlink (_addr.sun_path); | |
242 | ||
243 | if (_fd != -1) | |
244 | { | |
245 | (void) cygwin_shutdown (_fd, SHUT_WR); | |
246 | if (!_is_listening_endpoint) | |
247 | { | |
248 | char buf[BUFSIZ]; | |
249 | while (::read (_fd, buf, sizeof (buf)) > 0) | |
250 | {} | |
251 | } | |
252 | (void) ::close (_fd); | |
253 | _fd = -1; | |
254 | } | |
255 | ||
256 | _is_listening_endpoint = false; | |
f449bfef RC |
257 | } |
258 | ||
259 | ssize_t | |
1c001dd2 | 260 | transport_layer_sockets::read (void *const buf, const size_t buf_len) |
f449bfef | 261 | { |
1c001dd2 CS |
262 | assert (_fd != -1); |
263 | assert (!_is_listening_endpoint); | |
264 | ||
265 | assert (buf); | |
266 | assert (buf_len > 0); | |
267 | ||
268 | // verbose: debug_printf ("read (buf = %p, len = %u) [this = %p, fd = %d]", | |
269 | // buf, buf_len, this, _fd); | |
270 | ||
271 | char *read_buf = static_cast<char *> (buf); | |
272 | size_t read_buf_len = buf_len; | |
273 | ssize_t res = 0; | |
274 | ||
275 | while (read_buf_len != 0 | |
276 | && (res = ::read (_fd, read_buf, read_buf_len)) > 0) | |
277 | { | |
278 | read_buf += res; | |
279 | read_buf_len -= res; | |
280 | ||
281 | assert (read_buf_len >= 0); | |
282 | } | |
283 | ||
284 | if (res != -1) | |
285 | { | |
286 | if (res == 0) | |
1dcd520b | 287 | SET_ERRNO (EIO); // FIXME? |
1c001dd2 CS |
288 | |
289 | res = buf_len - read_buf_len; | |
290 | } | |
291 | ||
292 | if (res != static_cast<ssize_t> (buf_len)) | |
293 | debug_printf ("%d = read (buf = %p, len = %u) [this = %p, fd = %d]: %s", | |
294 | res, buf, buf_len, this, _fd, | |
1dcd520b | 295 | (res == -1 ? strerror (GET_ERRNO ()) : "EOF")); |
1c001dd2 CS |
296 | else |
297 | { | |
298 | // verbose: debug_printf ("%d = read (buf = %p, len = %u) [this = %p, fd = %d]", | |
299 | // res, buf, buf_len, this, _fd); | |
300 | } | |
301 | ||
302 | return res; | |
f449bfef RC |
303 | } |
304 | ||
305 | ssize_t | |
1c001dd2 | 306 | transport_layer_sockets::write (void *const buf, const size_t buf_len) |
f449bfef | 307 | { |
1c001dd2 CS |
308 | assert (_fd != -1); |
309 | assert (!_is_listening_endpoint); | |
310 | ||
311 | assert (buf); | |
312 | assert (buf_len > 0); | |
313 | ||
314 | // verbose: debug_printf ("write (buf = %p, len = %u) [this = %p, fd = %d]", | |
315 | // buf, buf_len, this, _fd); | |
316 | ||
317 | char *write_buf = static_cast<char *> (buf); | |
318 | size_t write_buf_len = buf_len; | |
319 | ssize_t res = 0; | |
320 | ||
321 | while (write_buf_len != 0 | |
322 | && (res = ::write (_fd, write_buf, write_buf_len)) > 0) | |
323 | { | |
324 | write_buf += res; | |
325 | write_buf_len -= res; | |
326 | ||
327 | assert (write_buf_len >= 0); | |
328 | } | |
329 | ||
330 | if (res != -1) | |
331 | { | |
332 | if (res == 0) | |
1dcd520b | 333 | SET_ERRNO (EIO); // FIXME? |
1c001dd2 CS |
334 | |
335 | res = buf_len - write_buf_len; | |
336 | } | |
337 | ||
338 | if (res != static_cast<ssize_t> (buf_len)) | |
339 | debug_printf ("%d = write (buf = %p, len = %u) [this = %p, fd = %d]: %s", | |
340 | res, buf, buf_len, this, _fd, | |
1dcd520b | 341 | (res == -1 ? strerror (GET_ERRNO ()) : "EOF")); |
1c001dd2 CS |
342 | else |
343 | { | |
344 | // verbose: debug_printf ("%d = write (buf = %p, len = %u) [this = %p, fd = %d]", | |
345 | // res, buf, buf_len, this, _fd); | |
346 | } | |
347 | ||
348 | return res; | |
f449bfef RC |
349 | } |
350 | ||
1c001dd2 | 351 | int |
f449bfef RC |
352 | transport_layer_sockets::connect () |
353 | { | |
1c001dd2 CS |
354 | assert (_fd == -1); |
355 | assert (!_is_accepted_endpoint); | |
356 | assert (!_is_listening_endpoint); | |
357 | ||
358 | static bool assume_cygserver = false; | |
359 | ||
360 | debug_printf ("connect () [this = %p]", this); | |
361 | ||
362 | for (int retries = 0; retries != MAX_CONNECT_RETRY; retries++) | |
f449bfef | 363 | { |
1c001dd2 CS |
364 | _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0); |
365 | ||
366 | if (_fd == -1) | |
367 | { | |
368 | system_printf ("failed to create UNIX domain socket: %s", | |
1dcd520b | 369 | strerror (GET_ERRNO ())); |
1c001dd2 CS |
370 | return -1; |
371 | } | |
372 | ||
373 | if (cygwin_connect (_fd, (struct sockaddr *) &_addr, _addr_len) == 0) | |
374 | { | |
375 | assume_cygserver = true; | |
376 | debug_printf ("0 = connect () [this = %p, fd = %d]", this, _fd); | |
377 | return 0; | |
378 | } | |
379 | ||
1dcd520b | 380 | if (!assume_cygserver || GET_ERRNO () != ECONNREFUSED) |
1c001dd2 | 381 | { |
1dcd520b | 382 | debug_printf ("failed to connect to server: %s", strerror (GET_ERRNO ())); |
1c001dd2 CS |
383 | (void) ::close (_fd); |
384 | _fd = -1; | |
385 | return -1; | |
386 | } | |
387 | ||
388 | (void) ::close (_fd); | |
389 | _fd = -1; | |
390 | Sleep (0); // Give the server a chance. | |
f449bfef | 391 | } |
1c001dd2 | 392 | |
1dcd520b | 393 | debug_printf ("failed to connect to server: %s", strerror (GET_ERRNO ())); |
1c001dd2 | 394 | return -1; |
f449bfef | 395 | } |