Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Server-side socket management |
| 3 | * |
| 4 | * Copyright (C) 1999 Marcus Meissner, Ove Kåven |
| 5 | * |
| 6 | * FIXME: we use read|write access in all cases. Shouldn't we depend that |
| 7 | * on the access of the current handle? |
| 8 | */ |
| 9 | |
Patrik Stridvall | 9633632 | 1999-10-24 22:13:47 +0000 | [diff] [blame] | 10 | #include "config.h" |
| 11 | |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 12 | #include <assert.h> |
| 13 | #include <fcntl.h> |
| 14 | #include <stdio.h> |
| 15 | #include <string.h> |
| 16 | #include <stdlib.h> |
| 17 | #include <errno.h> |
Patrik Stridvall | 9633632 | 1999-10-24 22:13:47 +0000 | [diff] [blame] | 18 | #ifdef HAVE_SYS_ERRNO_H |
| 19 | # include <sys/errno.h> |
| 20 | #endif |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 21 | #include <sys/time.h> |
| 22 | #include <sys/types.h> |
Patrik Stridvall | 9633632 | 1999-10-24 22:13:47 +0000 | [diff] [blame] | 23 | #ifdef HAVE_SYS_SOCKET_H |
| 24 | # include <sys/socket.h> |
| 25 | #endif |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 26 | #include <sys/ioctl.h> |
Patrik Stridvall | 9633632 | 1999-10-24 22:13:47 +0000 | [diff] [blame] | 27 | #ifdef HAVE_SYS_FILIO_H |
| 28 | # include <sys/filio.h> |
| 29 | #endif |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 30 | #include <time.h> |
| 31 | #include <unistd.h> |
| 32 | |
| 33 | #include "winerror.h" |
| 34 | #include "winbase.h" |
| 35 | #include "winsock2.h" |
| 36 | #include "process.h" |
| 37 | #include "handle.h" |
| 38 | #include "thread.h" |
| 39 | #include "request.h" |
| 40 | |
| 41 | struct sock |
| 42 | { |
| 43 | struct object obj; /* object header */ |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 44 | unsigned int state; /* status bits */ |
| 45 | unsigned int mask; /* event mask */ |
| 46 | unsigned int hmask; /* held (blocked) events */ |
| 47 | unsigned int pmask; /* pending events */ |
| 48 | struct event *event; /* event object */ |
| 49 | int errors[FD_MAX_EVENTS]; /* event errors */ |
| 50 | }; |
| 51 | |
| 52 | static void sock_dump( struct object *obj, int verbose ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 53 | static int sock_signaled( struct object *obj, struct thread *thread ); |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 54 | static int sock_get_poll_events( struct object *obj ); |
| 55 | static void sock_poll_event( struct object *obj, int event ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 56 | static int sock_get_fd( struct object *obj ); |
| 57 | static void sock_destroy( struct object *obj ); |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 58 | static int sock_get_error( int err ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 59 | static void sock_set_error(void); |
| 60 | |
| 61 | static const struct object_ops sock_ops = |
| 62 | { |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 63 | sizeof(struct sock), /* size */ |
| 64 | sock_dump, /* dump */ |
| 65 | add_queue, /* add_queue */ |
| 66 | remove_queue, /* remove_queue */ |
| 67 | sock_signaled, /* signaled */ |
| 68 | no_satisfied, /* satisfied */ |
| 69 | sock_get_poll_events, /* get_poll_events */ |
| 70 | sock_poll_event, /* poll_event */ |
Alexandre Julliard | 1ab243b | 2000-12-19 02:12:45 +0000 | [diff] [blame] | 71 | sock_get_fd, /* get_fd */ |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 72 | no_flush, /* flush */ |
| 73 | no_get_file_info, /* get_file_info */ |
| 74 | sock_destroy /* destroy */ |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 75 | }; |
| 76 | |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 77 | static void sock_reselect( struct sock *sock ) |
| 78 | { |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 79 | int ev = sock_get_poll_events( &sock->obj ); |
Ove Kaaven | 77c3055 | 2000-03-25 21:41:43 +0000 | [diff] [blame] | 80 | struct pollfd pfd; |
| 81 | |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 82 | if (debug_level) |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 83 | fprintf(stderr,"sock_reselect(%d): new mask %x\n", sock->obj.fd, ev); |
Ove Kaaven | 7a0f96c | 2000-09-06 19:40:23 +0000 | [diff] [blame] | 84 | |
| 85 | if (sock->obj.select == -1) { |
| 86 | /* previously unconnected socket, is this reselect supposed to connect it? */ |
Daniel Walker | c86517f | 2001-08-23 23:25:33 +0000 | [diff] [blame^] | 87 | if (!(sock->state & ~WS_FD_NONBLOCKING)) return; |
Ove Kaaven | 7a0f96c | 2000-09-06 19:40:23 +0000 | [diff] [blame] | 88 | /* ok, it is, attach it to the wineserver's main poll loop */ |
| 89 | add_select_user( &sock->obj ); |
| 90 | } |
| 91 | /* update condition mask */ |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 92 | set_select_events( &sock->obj, ev ); |
Ove Kaaven | 77c3055 | 2000-03-25 21:41:43 +0000 | [diff] [blame] | 93 | |
| 94 | /* check whether condition is satisfied already */ |
| 95 | pfd.fd = sock->obj.fd; |
| 96 | pfd.events = ev; |
| 97 | pfd.revents = 0; |
| 98 | poll( &pfd, 1, 0 ); |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 99 | if (pfd.revents) |
Ove Kaaven | 77c3055 | 2000-03-25 21:41:43 +0000 | [diff] [blame] | 100 | sock_poll_event( &sock->obj, pfd.revents); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | inline static int sock_error(int s) |
| 104 | { |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 105 | unsigned int optval = 0, optlen; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 106 | |
| 107 | optlen = sizeof(optval); |
| 108 | getsockopt(s, SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen); |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 109 | return optval ? sock_get_error(optval) : 0; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 110 | } |
| 111 | |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 112 | static void sock_poll_event( struct object *obj, int event ) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 113 | { |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 114 | struct sock *sock = (struct sock *)obj; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 115 | unsigned int emask; |
| 116 | assert( sock->obj.ops == &sock_ops ); |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 117 | if (debug_level) |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 118 | fprintf(stderr, "socket %d select event: %x\n", sock->obj.fd, event); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 119 | if (sock->state & WS_FD_CONNECT) |
| 120 | { |
| 121 | /* connecting */ |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 122 | if (event & POLLOUT) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 123 | { |
| 124 | /* we got connected */ |
| 125 | sock->state |= WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE; |
| 126 | sock->state &= ~WS_FD_CONNECT; |
| 127 | sock->pmask |= FD_CONNECT; |
| 128 | sock->errors[FD_CONNECT_BIT] = 0; |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 129 | if (debug_level) |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 130 | fprintf(stderr, "socket %d connection success\n", sock->obj.fd); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 131 | } |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 132 | else if (event & (POLLERR|POLLHUP)) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 133 | { |
| 134 | /* we didn't get connected? */ |
| 135 | sock->state &= ~WS_FD_CONNECT; |
| 136 | sock->pmask |= FD_CONNECT; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 137 | sock->errors[FD_CONNECT_BIT] = sock_error( sock->obj.fd ); |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 138 | if (debug_level) |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 139 | fprintf(stderr, "socket %d connection failure\n", sock->obj.fd); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 140 | } |
| 141 | } else |
| 142 | if (sock->state & WS_FD_LISTENING) |
| 143 | { |
| 144 | /* listening */ |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 145 | if (event & POLLIN) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 146 | { |
| 147 | /* incoming connection */ |
| 148 | sock->pmask |= FD_ACCEPT; |
| 149 | sock->errors[FD_ACCEPT_BIT] = 0; |
| 150 | sock->hmask |= FD_ACCEPT; |
| 151 | } |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 152 | else if (event & (POLLERR|POLLHUP)) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 153 | { |
| 154 | /* failed incoming connection? */ |
| 155 | sock->pmask |= FD_ACCEPT; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 156 | sock->errors[FD_ACCEPT_BIT] = sock_error( sock->obj.fd ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 157 | sock->hmask |= FD_ACCEPT; |
| 158 | } |
| 159 | } else |
| 160 | { |
| 161 | /* normal data flow */ |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 162 | if (event & POLLIN) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 163 | { |
Daniel Walker | c86517f | 2001-08-23 23:25:33 +0000 | [diff] [blame^] | 164 | char dummy; |
| 165 | |
| 166 | /* Linux 2.4 doesn't report POLLHUP if only one side of the socket |
| 167 | * has been closed, so we need to check for it explicitly here */ |
| 168 | if (!recv( sock->obj.fd, &dummy, 1, MSG_PEEK )) event = POLLHUP; |
| 169 | else |
| 170 | { |
| 171 | /* incoming data */ |
| 172 | sock->pmask |= FD_READ; |
| 173 | sock->hmask |= FD_READ; |
| 174 | sock->errors[FD_READ_BIT] = 0; |
| 175 | if (debug_level) |
| 176 | fprintf(stderr, "socket %d is readable\n", sock->obj.fd ); |
| 177 | } |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 178 | } |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 179 | if (event & POLLOUT) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 180 | { |
| 181 | sock->pmask |= FD_WRITE; |
| 182 | sock->hmask |= FD_WRITE; |
| 183 | sock->errors[FD_WRITE_BIT] = 0; |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 184 | if (debug_level) |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 185 | fprintf(stderr, "socket %d is writable\n", sock->obj.fd); |
| 186 | } |
| 187 | if (event & POLLPRI) |
| 188 | { |
| 189 | sock->pmask |= FD_OOB; |
| 190 | sock->hmask |= FD_OOB; |
Ove Kaaven | 77c3055 | 2000-03-25 21:41:43 +0000 | [diff] [blame] | 191 | sock->errors[FD_OOB_BIT] = 0; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 192 | if (debug_level) |
| 193 | fprintf(stderr, "socket %d got OOB data\n", sock->obj.fd); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 194 | } |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 195 | if (((event & POLLERR) || ((event & (POLLIN|POLLHUP)) == POLLHUP)) |
| 196 | && (sock->state & (WS_FD_READ|WS_FD_WRITE))) { |
| 197 | /* socket closing */ |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 198 | sock->errors[FD_CLOSE_BIT] = sock_error( sock->obj.fd ); |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 199 | sock->state &= ~(WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE); |
| 200 | sock->pmask |= FD_CLOSE; |
| 201 | if (debug_level) |
| 202 | fprintf(stderr, "socket %d aborted by error %d\n", |
| 203 | sock->obj.fd, sock->errors[FD_CLOSE_BIT]); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 204 | } |
| 205 | } |
| 206 | |
Ove Kaaven | 77c3055 | 2000-03-25 21:41:43 +0000 | [diff] [blame] | 207 | if (event & (POLLERR|POLLHUP)) |
| 208 | set_select_events( &sock->obj, -1 ); |
| 209 | else |
| 210 | sock_reselect( sock ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 211 | /* wake up anyone waiting for whatever just happened */ |
| 212 | emask = sock->pmask & sock->mask; |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 213 | if (debug_level && emask) |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 214 | fprintf(stderr, "socket %d pending events: %x\n", sock->obj.fd, emask); |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 215 | if (emask && sock->event) { |
| 216 | if (debug_level) fprintf(stderr, "signalling event ptr %p\n", sock->event); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 217 | set_event(sock->event); |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 218 | } |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 219 | |
| 220 | /* if anyone is stupid enough to wait on the socket object itself, |
| 221 | * maybe we should wake them up too, just in case? */ |
| 222 | wake_up( &sock->obj, 0 ); |
| 223 | } |
| 224 | |
| 225 | static void sock_dump( struct object *obj, int verbose ) |
| 226 | { |
| 227 | struct sock *sock = (struct sock *)obj; |
| 228 | assert( obj->ops == &sock_ops ); |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 229 | printf( "Socket fd=%d, state=%x, mask=%x, pending=%x, held=%x\n", |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 230 | sock->obj.fd, sock->state, |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 231 | sock->mask, sock->pmask, sock->hmask ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 232 | } |
| 233 | |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 234 | static int sock_signaled( struct object *obj, struct thread *thread ) |
| 235 | { |
| 236 | struct sock *sock = (struct sock *)obj; |
| 237 | assert( obj->ops == &sock_ops ); |
| 238 | |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 239 | return check_select_events( sock->obj.fd, sock_get_poll_events( &sock->obj ) ); |
| 240 | } |
| 241 | |
| 242 | static int sock_get_poll_events( struct object *obj ) |
| 243 | { |
| 244 | struct sock *sock = (struct sock *)obj; |
| 245 | unsigned int mask = sock->mask & sock->state & ~sock->hmask; |
| 246 | int ev = 0; |
| 247 | |
| 248 | assert( obj->ops == &sock_ops ); |
| 249 | |
| 250 | if (sock->state & WS_FD_CONNECT) |
| 251 | /* connecting, wait for writable */ |
| 252 | return POLLOUT; |
| 253 | if (sock->state & WS_FD_LISTENING) |
| 254 | /* listening, wait for readable */ |
| 255 | return (sock->hmask & FD_ACCEPT) ? 0 : POLLIN; |
| 256 | |
| 257 | if (mask & FD_READ) ev |= POLLIN | POLLPRI; |
| 258 | if (mask & FD_WRITE) ev |= POLLOUT; |
| 259 | return ev; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | static int sock_get_fd( struct object *obj ) |
| 263 | { |
| 264 | struct sock *sock = (struct sock *)obj; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 265 | assert( obj->ops == &sock_ops ); |
Alexandre Julliard | 63411db | 2000-12-22 21:12:36 +0000 | [diff] [blame] | 266 | return sock->obj.fd; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 267 | } |
| 268 | |
| 269 | static void sock_destroy( struct object *obj ) |
| 270 | { |
| 271 | struct sock *sock = (struct sock *)obj; |
| 272 | assert( obj->ops == &sock_ops ); |
| 273 | |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 274 | /* FIXME: special socket shutdown stuff? */ |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 275 | if (sock->event) |
| 276 | { |
| 277 | /* if the service thread was waiting for the event object, |
| 278 | * we should now signal it, to let the service thread |
| 279 | * object detect that it is now orphaned... */ |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 280 | if (sock->mask & WS_FD_SERVEVENT) |
| 281 | set_event( sock->event ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 282 | /* we're through with it */ |
| 283 | release_object( sock->event ); |
| 284 | } |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 285 | } |
| 286 | |
| 287 | /* create a new and unconnected socket */ |
| 288 | static struct object *create_socket( int family, int type, int protocol ) |
| 289 | { |
| 290 | struct sock *sock; |
Ove Kaaven | 3669b94 | 1999-11-07 05:23:02 +0000 | [diff] [blame] | 291 | int sockfd; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 292 | |
Ove Kaaven | 3669b94 | 1999-11-07 05:23:02 +0000 | [diff] [blame] | 293 | sockfd = socket( family, type, protocol ); |
| 294 | if (debug_level) |
| 295 | fprintf(stderr,"socket(%d,%d,%d)=%d\n",family,type,protocol,sockfd); |
| 296 | if (sockfd == -1) { |
| 297 | sock_set_error(); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 298 | return NULL; |
Ove Kaaven | 3669b94 | 1999-11-07 05:23:02 +0000 | [diff] [blame] | 299 | } |
| 300 | fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ |
Ove Kaaven | 7a0f96c | 2000-09-06 19:40:23 +0000 | [diff] [blame] | 301 | if (!(sock = alloc_object( &sock_ops, -1 ))) return NULL; |
| 302 | sock->obj.fd = sockfd; |
| 303 | sock->state = (type != SOCK_STREAM) ? (WS_FD_READ|WS_FD_WRITE) : 0; |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 304 | sock->mask = 0; |
| 305 | sock->hmask = 0; |
| 306 | sock->pmask = 0; |
| 307 | sock->event = NULL; |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 308 | sock_reselect( sock ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 309 | clear_error(); |
| 310 | return &sock->obj; |
| 311 | } |
| 312 | |
| 313 | /* accept a socket (creates a new fd) */ |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 314 | static struct object *accept_socket( handle_t handle ) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 315 | { |
| 316 | struct sock *acceptsock; |
| 317 | struct sock *sock; |
| 318 | int acceptfd; |
| 319 | struct sockaddr saddr; |
| 320 | int slen; |
| 321 | |
| 322 | sock=(struct sock*)get_handle_obj(current->process,handle, |
| 323 | GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); |
| 324 | if (!sock) |
| 325 | return NULL; |
| 326 | /* Try to accept(2). We can't be safe that this an already connected socket |
| 327 | * or that accept() is allowed on it. In those cases we will get -1/errno |
| 328 | * return. |
| 329 | */ |
| 330 | slen = sizeof(saddr); |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 331 | acceptfd = accept(sock->obj.fd,&saddr,&slen); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 332 | if (acceptfd==-1) { |
| 333 | sock_set_error(); |
| 334 | release_object( sock ); |
| 335 | return NULL; |
| 336 | } |
Ove Kaaven | 7a0f96c | 2000-09-06 19:40:23 +0000 | [diff] [blame] | 337 | if (!(acceptsock = alloc_object( &sock_ops, -1 ))) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 338 | { |
| 339 | release_object( sock ); |
| 340 | return NULL; |
| 341 | } |
| 342 | |
Stephane Lussier | 0d5f1ab | 2000-09-27 22:27:33 +0000 | [diff] [blame] | 343 | /* newly created socket gets the same properties of the listening socket */ |
| 344 | fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ |
Ove Kaaven | 7a0f96c | 2000-09-06 19:40:23 +0000 | [diff] [blame] | 345 | acceptsock->obj.fd = acceptfd; |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 346 | acceptsock->state = WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE; |
Stephane Lussier | 0d5f1ab | 2000-09-27 22:27:33 +0000 | [diff] [blame] | 347 | if (sock->state & WS_FD_NONBLOCKING) |
| 348 | acceptsock->state |= WS_FD_NONBLOCKING; |
Alexandre Julliard | 247b8ae | 1999-12-13 00:16:44 +0000 | [diff] [blame] | 349 | acceptsock->mask = sock->mask; |
| 350 | acceptsock->hmask = 0; |
| 351 | acceptsock->pmask = 0; |
| 352 | acceptsock->event = NULL; |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 353 | if (sock->event && !(sock->mask & WS_FD_SERVEVENT)) |
| 354 | acceptsock->event = (struct event *)grab_object( sock->event ); |
Jeremy White | 942010a | 1999-11-07 19:15:19 +0000 | [diff] [blame] | 355 | |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 356 | sock_reselect( acceptsock ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 357 | clear_error(); |
| 358 | sock->pmask &= ~FD_ACCEPT; |
| 359 | sock->hmask &= ~FD_ACCEPT; |
Stephane Lussier | 21b099f | 2000-10-13 17:04:52 +0000 | [diff] [blame] | 360 | sock_reselect( sock ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 361 | release_object( sock ); |
| 362 | return &acceptsock->obj; |
| 363 | } |
| 364 | |
| 365 | /* set the last error depending on errno */ |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 366 | static int sock_get_error( int err ) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 367 | { |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 368 | switch (err) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 369 | { |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 370 | case EINTR: return WSAEINTR; break; |
| 371 | case EBADF: return WSAEBADF; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 372 | case EPERM: |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 373 | case EACCES: return WSAEACCES; break; |
| 374 | case EFAULT: return WSAEFAULT; break; |
| 375 | case EINVAL: return WSAEINVAL; break; |
| 376 | case EMFILE: return WSAEMFILE; break; |
| 377 | case EWOULDBLOCK: return WSAEWOULDBLOCK; break; |
| 378 | case EINPROGRESS: return WSAEINPROGRESS; break; |
| 379 | case EALREADY: return WSAEALREADY; break; |
| 380 | case ENOTSOCK: return WSAENOTSOCK; break; |
| 381 | case EDESTADDRREQ: return WSAEDESTADDRREQ; break; |
| 382 | case EMSGSIZE: return WSAEMSGSIZE; break; |
| 383 | case EPROTOTYPE: return WSAEPROTOTYPE; break; |
| 384 | case ENOPROTOOPT: return WSAENOPROTOOPT; break; |
| 385 | case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT; break; |
| 386 | case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT; break; |
| 387 | case EOPNOTSUPP: return WSAEOPNOTSUPP; break; |
| 388 | case EPFNOSUPPORT: return WSAEPFNOSUPPORT; break; |
| 389 | case EAFNOSUPPORT: return WSAEAFNOSUPPORT; break; |
| 390 | case EADDRINUSE: return WSAEADDRINUSE; break; |
| 391 | case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL; break; |
| 392 | case ENETDOWN: return WSAENETDOWN; break; |
| 393 | case ENETUNREACH: return WSAENETUNREACH; break; |
| 394 | case ENETRESET: return WSAENETRESET; break; |
| 395 | case ECONNABORTED: return WSAECONNABORTED; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 396 | case EPIPE: |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 397 | case ECONNRESET: return WSAECONNRESET; break; |
| 398 | case ENOBUFS: return WSAENOBUFS; break; |
| 399 | case EISCONN: return WSAEISCONN; break; |
| 400 | case ENOTCONN: return WSAENOTCONN; break; |
| 401 | case ESHUTDOWN: return WSAESHUTDOWN; break; |
| 402 | case ETOOMANYREFS: return WSAETOOMANYREFS; break; |
| 403 | case ETIMEDOUT: return WSAETIMEDOUT; break; |
| 404 | case ECONNREFUSED: return WSAECONNREFUSED; break; |
| 405 | case ELOOP: return WSAELOOP; break; |
| 406 | case ENAMETOOLONG: return WSAENAMETOOLONG; break; |
| 407 | case EHOSTDOWN: return WSAEHOSTDOWN; break; |
| 408 | case EHOSTUNREACH: return WSAEHOSTUNREACH; break; |
| 409 | case ENOTEMPTY: return WSAENOTEMPTY; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 410 | #ifdef EPROCLIM |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 411 | case EPROCLIM: return WSAEPROCLIM; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 412 | #endif |
| 413 | #ifdef EUSERS |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 414 | case EUSERS: return WSAEUSERS; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 415 | #endif |
| 416 | #ifdef EDQUOT |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 417 | case EDQUOT: return WSAEDQUOT; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 418 | #endif |
| 419 | #ifdef ESTALE |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 420 | case ESTALE: return WSAESTALE; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 421 | #endif |
| 422 | #ifdef EREMOTE |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 423 | case EREMOTE: return WSAEREMOTE; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 424 | #endif |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 425 | default: errno=err; perror("sock_set_error"); return ERROR_UNKNOWN; break; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 426 | } |
| 427 | } |
| 428 | |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 429 | /* set the last error depending on errno */ |
| 430 | static void sock_set_error(void) |
| 431 | { |
| 432 | set_error( sock_get_error( errno ) ); |
| 433 | } |
| 434 | |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 435 | /* create a socket */ |
| 436 | DECL_HANDLER(create_socket) |
| 437 | { |
| 438 | struct object *obj; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 439 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 440 | req->handle = 0; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 441 | if ((obj = create_socket( req->family, req->type, req->protocol )) != NULL) |
| 442 | { |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 443 | req->handle = alloc_handle( current->process, obj, req->access, req->inherit ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 444 | release_object( obj ); |
| 445 | } |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 446 | } |
| 447 | |
| 448 | /* accept a socket */ |
| 449 | DECL_HANDLER(accept_socket) |
| 450 | { |
| 451 | struct object *obj; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 452 | |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 453 | req->handle = 0; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 454 | if ((obj = accept_socket( req->lhandle )) != NULL) |
| 455 | { |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 456 | req->handle = alloc_handle( current->process, obj, req->access, req->inherit ); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 457 | release_object( obj ); |
| 458 | } |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 459 | } |
| 460 | |
| 461 | /* set socket event parameters */ |
| 462 | DECL_HANDLER(set_socket_event) |
| 463 | { |
| 464 | struct sock *sock; |
| 465 | struct event *oevent; |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 466 | unsigned int omask; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 467 | |
| 468 | sock=(struct sock*)get_handle_obj(current->process,req->handle,GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); |
| 469 | if (!sock) |
| 470 | return; |
| 471 | oevent = sock->event; |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 472 | omask = sock->mask; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 473 | sock->mask = req->mask; |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 474 | sock->event = get_event_obj( current->process, req->event, EVENT_MODIFY_STATE ); |
| 475 | if (debug_level && sock->event) fprintf(stderr, "event ptr: %p\n", sock->event); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 476 | sock_reselect( sock ); |
| 477 | if (sock->mask) |
| 478 | sock->state |= WS_FD_NONBLOCKING; |
Stephane Lussier | 56adb25 | 2000-07-16 18:14:01 +0000 | [diff] [blame] | 479 | |
| 480 | /* if a network event is pending, signal the event object |
| 481 | it is possible that FD_CONNECT or FD_ACCEPT network events has happened |
| 482 | before a WSAEventSelect() was done on it. |
| 483 | (when dealing with Asynchronous socket) */ |
| 484 | if (sock->pmask & sock->mask) |
| 485 | set_event(sock->event); |
| 486 | |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 487 | if (oevent) |
| 488 | { |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 489 | if ((oevent != sock->event) && (omask & WS_FD_SERVEVENT)) |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 490 | /* if the service thread was waiting for the old event object, |
| 491 | * we should now signal it, to let the service thread |
| 492 | * object detect that it is now orphaned... */ |
| 493 | set_event( oevent ); |
| 494 | /* we're through with it */ |
| 495 | release_object( oevent ); |
| 496 | } |
| 497 | release_object( &sock->obj ); |
| 498 | } |
| 499 | |
| 500 | /* get socket event parameters */ |
| 501 | DECL_HANDLER(get_socket_event) |
| 502 | { |
| 503 | struct sock *sock; |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 504 | size_t size; |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 505 | |
| 506 | sock=(struct sock*)get_handle_obj(current->process,req->handle,GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); |
| 507 | if (!sock) |
| 508 | { |
| 509 | req->mask = 0; |
| 510 | req->pmask = 0; |
| 511 | req->state = 0; |
| 512 | set_error(WSAENOTSOCK); |
| 513 | return; |
| 514 | } |
| 515 | req->mask = sock->mask; |
| 516 | req->pmask = sock->pmask; |
| 517 | req->state = sock->state; |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 518 | size = min( get_req_data_size(req), sizeof(sock->errors) ); |
| 519 | memcpy( get_req_data(req), sock->errors, size ); |
| 520 | set_req_data_size( req, size ); |
| 521 | |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 522 | if (req->service) |
| 523 | { |
| 524 | if (req->s_event) |
| 525 | { |
Ove Kaaven | f45608f | 1999-10-23 16:53:34 +0000 | [diff] [blame] | 526 | struct event *sevent = get_event_obj(current->process, req->s_event, 0); |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 527 | if (sevent == sock->event) |
| 528 | req->s_event = 0; |
| 529 | release_object( sevent ); |
| 530 | } |
| 531 | if (!req->s_event) |
| 532 | { |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 533 | if (req->c_event) |
| 534 | { |
| 535 | struct event *cevent = get_event_obj(current->process, req->c_event, EVENT_MODIFY_STATE); |
| 536 | reset_event( cevent ); |
| 537 | release_object( cevent ); |
| 538 | } |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 539 | sock->pmask = 0; |
| 540 | sock_reselect( sock ); |
| 541 | } |
| 542 | else set_error(WSAEINVAL); |
| 543 | } |
| 544 | release_object( &sock->obj ); |
| 545 | } |
| 546 | |
| 547 | /* re-enable pending socket events */ |
| 548 | DECL_HANDLER(enable_socket_event) |
| 549 | { |
| 550 | struct sock *sock; |
| 551 | |
| 552 | sock=(struct sock*)get_handle_obj(current->process,req->handle,GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,&sock_ops); |
| 553 | if (!sock) |
| 554 | return; |
| 555 | sock->pmask &= ~req->mask; /* is this safe? */ |
| 556 | sock->hmask &= ~req->mask; |
| 557 | sock->state |= req->sstate; |
| 558 | sock->state &= ~req->cstate; |
| 559 | sock_reselect( sock ); |
Ove Kaaven | cb98a6e | 2000-03-26 18:21:16 +0000 | [diff] [blame] | 560 | |
| 561 | /* service trigger */ |
| 562 | if (req->mask & WS_FD_SERVEVENT) |
| 563 | { |
| 564 | sock->pmask |= WS_FD_SERVEVENT; |
| 565 | if (sock->event) { |
| 566 | if (debug_level) fprintf(stderr, "signalling service event ptr %p\n", sock->event); |
| 567 | set_event(sock->event); |
| 568 | } |
| 569 | } |
| 570 | |
Ove Kaaven | 019211f | 1999-10-13 16:05:37 +0000 | [diff] [blame] | 571 | release_object( &sock->obj ); |
| 572 | } |