Cygwin: select: Fix FD_CLOSE handling
An FD_CLOSE event sets a socket descriptor ready for writing. This is incorrect if the FD_CLOSE is a result of shutdown(SHUT_RD). Only set the socket descriptor ready for writing if the FD_CLOSE is indicating an connection abort or reset error condition. This requires to tweak fhandler_socket_wsock::evaluate_events. FD_CLOSE in conjunction with FD_ACCEPT/FD_CONNECT special cases a shutdown condition by setting an error code. This is correct for accept/connect, but not for select. In this case, make sure to return with an error code only if FD_CLOSE indicates a connection error. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
		
							parent
							
								
									caa78917b6
								
							
						
					
					
						commit
						ef95c03522
					
				|  | @ -361,20 +361,30 @@ fhandler_socket_wsock::evaluate_events (const long event_mask, long &events, | |||
| 	  wsock_events->events |= FD_WRITE; | ||||
| 	  wsock_events->connect_errorcode = 0; | ||||
| 	} | ||||
|       /* This test makes accept/connect behave as on Linux when accept/connect
 | ||||
|          is called on a socket for which shutdown has been called.  The second | ||||
| 	 half of this code is in the shutdown method. */ | ||||
|       if (events & FD_CLOSE) | ||||
| 	{ | ||||
| 	  if ((event_mask & FD_ACCEPT) && saw_shutdown_read ()) | ||||
| 	  if (evts.iErrorCode[FD_CLOSE_BIT]) | ||||
| 	    { | ||||
| 	      WSASetLastError (WSAEINVAL); | ||||
| 	      WSASetLastError (evts.iErrorCode[FD_CLOSE_BIT]); | ||||
| 	      ret = SOCKET_ERROR; | ||||
| 	    } | ||||
| 	  if (event_mask & FD_CONNECT) | ||||
| 	  /* This test makes accept/connect behave as on Linux when accept/
 | ||||
| 	     connect is called on a socket for which shutdown has been called. | ||||
| 	     The second half of this code is in the shutdown method.  Note that | ||||
| 	     we only do this when called from accept/connect, not from select. | ||||
| 	     In this case erase == false, just as with read (MSG_PEEK). */ | ||||
| 	  if (erase) | ||||
| 	    { | ||||
| 	      WSASetLastError (WSAECONNRESET); | ||||
| 	      ret = SOCKET_ERROR; | ||||
| 	      if ((event_mask & FD_ACCEPT) && saw_shutdown_read ()) | ||||
| 		{ | ||||
| 		  WSASetLastError (WSAEINVAL); | ||||
| 		  ret = SOCKET_ERROR; | ||||
| 		} | ||||
| 	      if (event_mask & FD_CONNECT) | ||||
| 		{ | ||||
| 		  WSASetLastError (WSAECONNRESET); | ||||
| 		  ret = SOCKET_ERROR; | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
|       if (erase) | ||||
|  |  | |||
|  | @ -1709,7 +1709,8 @@ peek_socket (select_record *me, bool) | |||
|   fhandler_socket_wsock *fh = (fhandler_socket_wsock *) me->fh; | ||||
|   long events; | ||||
|   /* Don't play with the settings again, unless having taken a deep look into
 | ||||
|      Richard W. Stevens Network Programming book.  Thank you. */ | ||||
|      Richard W. Stevens Network Programming book and how these flags are | ||||
|      defined in Winsock.  Thank you. */ | ||||
|   long evt_mask = (me->read_selected ? (FD_READ | FD_ACCEPT | FD_CLOSE) : 0) | ||||
| 		| (me->write_selected ? (FD_WRITE | FD_CONNECT | FD_CLOSE) : 0) | ||||
| 		| (me->except_selected ? FD_OOB : 0); | ||||
|  | @ -1717,7 +1718,9 @@ peek_socket (select_record *me, bool) | |||
|   if (me->read_selected) | ||||
|     me->read_ready |= ret || !!(events & (FD_READ | FD_ACCEPT | FD_CLOSE)); | ||||
|   if (me->write_selected) | ||||
|     me->write_ready |= ret || !!(events & (FD_WRITE | FD_CONNECT | FD_CLOSE)); | ||||
|     /* Don't check for FD_CLOSE here.  Only an error case (ret == -1)
 | ||||
|        will set ready for writing. */ | ||||
|     me->write_ready |= ret || !!(events & (FD_WRITE | FD_CONNECT)); | ||||
|   if (me->except_selected) | ||||
|     me->except_ready |= !!(events & FD_OOB); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue