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