Improve accept(); allow select(2) on listeners
Changes:
    * Add validation to accept() to ensure file descriptors provided
      refer to SOCK_STREAM sockets in the SOCK_LISTENING state
    * Rather than writing a reply to the patty client socket when
      accepting a SABM or SABME request, write a message to the
      remote end of the listening socket; this avoids issues wherein
      a client receives an unexpected accept() response that may be
      unrelated to another pending request; this also allows client
      code to use select(2) on listening sockets
    * In patty_client_accept(), send the initial request to validate
      that the local socket can accept connections, and then wait for
      a connection to be made, reading a message written to the
      listening socket from the patty server
    * Allow select(2) to notify on accepted connections
			
			
This commit is contained in:
		
							parent
							
								
									0b8ce4f775
								
							
						
					
					
						commit
						20cacf4bed
					
				
					 3 changed files with 72 additions and 30 deletions
				
			
		|  | @ -120,11 +120,15 @@ typedef struct _patty_client_accept_request { | |||
| } patty_client_accept_request; | ||||
| 
 | ||||
| typedef struct _patty_client_accept_response { | ||||
|     int fd; | ||||
|     int ret; | ||||
|     int eno; | ||||
| } patty_client_accept_response; | ||||
| 
 | ||||
| typedef struct _patty_client_accept_message { | ||||
|     int fd; | ||||
|     patty_ax25_addr peer; | ||||
|     char path[PATTY_AX25_SOCK_PATH_SIZE]; | ||||
| } patty_client_accept_response; | ||||
| } patty_client_accept_message; | ||||
| 
 | ||||
| int patty_client_accept(patty_client *client, | ||||
|                         int fd, | ||||
|  |  | |||
							
								
								
									
										26
									
								
								src/client.c
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								src/client.c
									
										
									
									
									
								
							|  | @ -312,6 +312,7 @@ int patty_client_accept(patty_client *client, | |||
| 
 | ||||
|     patty_client_accept_request request; | ||||
|     patty_client_accept_response response; | ||||
|     patty_client_accept_message message; | ||||
| 
 | ||||
|     patty_client_sock *local, | ||||
|                       *remote; | ||||
|  | @ -341,18 +342,33 @@ int patty_client_accept(patty_client *client, | |||
|         goto error_io; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * First, the server will tell us if the fd specified in accept() is indeed | ||||
|      * accepting connections. | ||||
|      */ | ||||
|     if (read(client->fd, &response, sizeof(response)) < 0) { | ||||
|         goto error_io; | ||||
|     } | ||||
| 
 | ||||
|     if (response.fd >= 0) { | ||||
|         memcpy(peer, &response.peer, sizeof(*peer)); | ||||
|     if (response.ret < 0) { | ||||
|         errno = response.eno; | ||||
| 
 | ||||
|         remote->fd = response.fd; | ||||
| 
 | ||||
|         strncpy(remote->path, response.path, sizeof(remote->path)); | ||||
|         return response.ret; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * Next, we will wait for the server to receive a SABM or SABME frame, and | ||||
|      * notify us via the listening socket that a connection has been accepted. | ||||
|      */ | ||||
|     if (read(fd, &message, sizeof(message)) < 0) { | ||||
|         goto error_io; | ||||
|     } | ||||
| 
 | ||||
|     remote->fd = message.fd; | ||||
| 
 | ||||
|     memcpy(peer, &message.peer, sizeof(*peer)); | ||||
|     strncpy(remote->path, message.path, sizeof(remote->path)); | ||||
| 
 | ||||
|     if ((pty = open(remote->path, O_RDWR)) < 0) { | ||||
|         goto error_open; | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										64
									
								
								src/server.c
									
										
									
									
									
								
							
							
						
						
									
										64
									
								
								src/server.c
									
										
									
									
									
								
							|  | @ -514,26 +514,35 @@ int patty_ax25_server_add_route(patty_ax25_server *server, | |||
| } | ||||
| 
 | ||||
| static int respond_accept(int client, | ||||
|                           int fd, | ||||
|                           int eno, | ||||
|                           int ret, | ||||
|                           int eno) { | ||||
|     patty_client_accept_response response = { | ||||
|         .ret = ret, | ||||
|         .eno = eno | ||||
|     }; | ||||
| 
 | ||||
|     return write(client, &response, sizeof(response)); | ||||
| } | ||||
| 
 | ||||
| static int notify_accept(int local, | ||||
|                          int remote, | ||||
|                          patty_ax25_addr *peer, | ||||
|                          char *path) { | ||||
|     patty_client_accept_response response; | ||||
|     patty_client_accept_message message; | ||||
| 
 | ||||
|     memset(&response, '\0', sizeof(response)); | ||||
|     memset(&message, '\0', sizeof(message)); | ||||
| 
 | ||||
|     response.fd  = fd; | ||||
|     response.eno = eno; | ||||
|     message.fd = remote; | ||||
| 
 | ||||
|     if (peer) { | ||||
|         memcpy(&response.peer, peer, sizeof(response.peer)); | ||||
|         memcpy(&message.peer, peer, sizeof(message.peer)); | ||||
|     } | ||||
| 
 | ||||
|     if (path) { | ||||
|         strncpy(response.path, path, sizeof(response.path)-1); | ||||
|         strncpy(message.path, path, sizeof(message.path)-1); | ||||
|     } | ||||
| 
 | ||||
|     return write(client, &response, sizeof(response)); | ||||
|     return write(local, &message, sizeof(message)); | ||||
| } | ||||
| 
 | ||||
| static int respond_connect(int client, int ret, int eno) { | ||||
|  | @ -770,13 +779,18 @@ static int server_accept(patty_ax25_server *server, | |||
|     } | ||||
| 
 | ||||
|     if ((sock = sock_by_fd(server->socks_by_fd, request.fd)) == NULL) { | ||||
|         goto error_sock_by_fd; | ||||
|         return respond_accept(client, -1, EBADF); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
|     if (sock->type != PATTY_AX25_SOCK_STREAM) { | ||||
|         return respond_accept(client, -1, EOPNOTSUPP); | ||||
|     } | ||||
| 
 | ||||
| error_sock_by_fd: | ||||
|     return respond_accept(client, -1, EBADF, NULL, NULL); | ||||
|     if (sock->state != PATTY_AX25_SOCK_LISTENING) { | ||||
|         return respond_accept(client, -1, EINVAL); | ||||
|     } | ||||
| 
 | ||||
|     return respond_accept(client, 0, 0); | ||||
| 
 | ||||
| error_io: | ||||
|     return -1; | ||||
|  | @ -1228,8 +1242,10 @@ static int handle_sabm(patty_ax25_server *server, | |||
|     patty_ax25_sock *local, *remote; | ||||
| 
 | ||||
|     if ((local = sock_by_addr(server->socks_local, | ||||
|                               &frame->dest)) == NULL) { | ||||
|         return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); | ||||
|                               &frame->dest)) == NULL | ||||
|      || local->type  != PATTY_AX25_SOCK_STREAM | ||||
|      || local->state != PATTY_AX25_SOCK_LISTENING) { | ||||
|         goto reply_dm; | ||||
|     } | ||||
| 
 | ||||
|     if ((client = client_by_sock(server, local)) < 0) { | ||||
|  | @ -1254,6 +1270,8 @@ static int handle_sabm(patty_ax25_server *server, | |||
|         save_reply_addr(remote, frame); | ||||
| 
 | ||||
|         created = 1; | ||||
|     } else if (remote->state != PATTY_AX25_SOCK_PENDING_ACCEPT) { | ||||
|         goto reply_dm; | ||||
|     } | ||||
| 
 | ||||
|     remote->state = PATTY_AX25_SOCK_ESTABLISHED; | ||||
|  | @ -1280,15 +1298,18 @@ static int handle_sabm(patty_ax25_server *server, | |||
| 
 | ||||
|     fd_watch(server, remote->fd); | ||||
| 
 | ||||
|     if (respond_accept(client, remote->fd, 0, &frame->src, remote->pty) < 0) { | ||||
|         goto error_respond_accept; | ||||
|     if (notify_accept(local->fd, remote->fd, &remote->remote, remote->pty) < 0) { | ||||
|         goto error_notify_accept; | ||||
|     } | ||||
| 
 | ||||
|     patty_timer_start(&remote->timer_t3, PATTY_AX25_SOCK_DEFAULT_KEEPALIVE); | ||||
| 
 | ||||
|     return reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL); | ||||
| 
 | ||||
| error_respond_accept: | ||||
| reply_dm: | ||||
|     return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); | ||||
| 
 | ||||
| error_notify_accept: | ||||
| error_sock_realloc_bufs: | ||||
| error_sock_save: | ||||
|     patty_ax25_sock_destroy(remote); | ||||
|  | @ -1673,9 +1694,7 @@ static int handle_xid(patty_ax25_server *server, | |||
|         patty_ax25_sock_params_max(remote); | ||||
| 
 | ||||
|         if (patty_ax25_sock_params_negotiate(remote, ¶ms) < 0) { | ||||
|             patty_ax25_sock_destroy(remote); | ||||
| 
 | ||||
|             return respond_accept(client, -1, errno, NULL, NULL); | ||||
|             goto error_sock_params_negotiate; | ||||
|         } | ||||
| 
 | ||||
|         save_reply_addr(remote, frame); | ||||
|  | @ -1691,6 +1710,9 @@ reply_dm: | |||
|     return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL); | ||||
| 
 | ||||
| error_sock_save: | ||||
| error_sock_params_negotiate: | ||||
|     patty_ax25_sock_destroy(remote); | ||||
| 
 | ||||
| error_sock_new: | ||||
| error_client_by_sock: | ||||
| error_io: | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue