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