]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygserver/transport_sockets.cc
Remove superfluous libgloss/ directory names from recent ChangeLog entries.
[newlib-cygwin.git] / winsup / cygserver / transport_sockets.cc
CommitLineData
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 7This file is part of Cygwin.
f449bfef 8
1c001dd2
CS
9This software is a copyrighted work licensed under the terms of the
10Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11details. */
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
43extern "C" int cygwin_accept (int fd, struct sockaddr *, int *len);
44extern "C" int cygwin_bind (int fd, const struct sockaddr *, int len);
45extern "C" int cygwin_connect (int fd, const struct sockaddr *, int len);
46extern "C" int cygwin_listen (int fd, int backlog);
47extern "C" int cygwin_shutdown (int fd, int how);
48extern "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
61enum
62 {
63 MAX_CONNECT_RETRY = 64
64 };
65
66transport_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
77transport_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
90transport_layer_sockets::~transport_layer_sockets ()
91{
92 close ();
93}
94
95#ifndef __INSIDE_CYGWIN__
96
97int
f449bfef
RC
98transport_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
192class transport_layer_sockets *
1c001dd2 193transport_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 235void
1c001dd2 236transport_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
259ssize_t
1c001dd2 260transport_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
305ssize_t
1c001dd2 306transport_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 351int
f449bfef
RC
352transport_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}
This page took 0.164444 seconds and 5 git commands to generate.