sockets: change inet_connect() to support nonblock socket
Add a bool argument to inet_connect() to assign if set socket to block/nonblock, and delete original argument 'socktype' that is unused. Add a new argument to inet_connect()/inet_connect_opts(), to pass back connect error by error class. Retry to connect when -EINTR is got. Connect's successful for nonblock socket when following errors are got, user should wait for connecting by select(): -EINPROGRESS -EWOULDBLOCK (win32) -WSAEALREADY (win32) Change nbd, vnc to use new interface. Signed-off-by: Amos Kong <akong@redhat.com> Reviewed-by: Orit Wasserman <owasserm@redhat.com> Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
		
							parent
							
								
									aed3d11df6
								
							
						
					
					
						commit
						a6ba35b3be
					
				
							
								
								
									
										2
									
								
								nbd.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								nbd.c
									
									
									
									
									
								
							| @ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port) | ||||
| 
 | ||||
| int tcp_socket_outgoing_spec(const char *address_and_port) | ||||
| { | ||||
|     return inet_connect(address_and_port, SOCK_STREAM); | ||||
|     return inet_connect(address_and_port, true, NULL); | ||||
| } | ||||
| 
 | ||||
| int tcp_socket_incoming(const char *address, uint16_t port) | ||||
|  | ||||
| @ -2446,7 +2446,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) | ||||
|         if (is_listen) { | ||||
|             fd = inet_listen_opts(opts, 0); | ||||
|         } else { | ||||
|             fd = inet_connect_opts(opts); | ||||
|             fd = inet_connect_opts(opts, NULL); | ||||
|         } | ||||
|     } | ||||
|     if (fd < 0) { | ||||
|  | ||||
| @ -51,6 +51,9 @@ static QemuOptsList dummy_opts = { | ||||
|         },{ | ||||
|             .name = "ipv6", | ||||
|             .type = QEMU_OPT_BOOL, | ||||
|         },{ | ||||
|             .name = "block", | ||||
|             .type = QEMU_OPT_BOOL, | ||||
|         }, | ||||
|         { /* end if list */ } | ||||
|     }, | ||||
| @ -194,7 +197,7 @@ listen: | ||||
|     return slisten; | ||||
| } | ||||
| 
 | ||||
| int inet_connect_opts(QemuOpts *opts) | ||||
| int inet_connect_opts(QemuOpts *opts, Error **errp) | ||||
| { | ||||
|     struct addrinfo ai,*res,*e; | ||||
|     const char *addr; | ||||
| @ -202,6 +205,7 @@ int inet_connect_opts(QemuOpts *opts) | ||||
|     char uaddr[INET6_ADDRSTRLEN+1]; | ||||
|     char uport[33]; | ||||
|     int sock,rc; | ||||
|     bool block; | ||||
| 
 | ||||
|     memset(&ai,0, sizeof(ai)); | ||||
|     ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; | ||||
| @ -210,8 +214,10 @@ int inet_connect_opts(QemuOpts *opts) | ||||
| 
 | ||||
|     addr = qemu_opt_get(opts, "host"); | ||||
|     port = qemu_opt_get(opts, "port"); | ||||
|     block = qemu_opt_get_bool(opts, "block", 0); | ||||
|     if (addr == NULL || port == NULL) { | ||||
|         fprintf(stderr, "inet_connect: host and/or port not specified\n"); | ||||
|         error_set(errp, QERR_SOCKET_CREATE_FAILED); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
| @ -224,6 +230,7 @@ int inet_connect_opts(QemuOpts *opts) | ||||
|     if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { | ||||
|         fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, | ||||
|                 gai_strerror(rc)); | ||||
|         error_set(errp, QERR_SOCKET_CREATE_FAILED); | ||||
| 	return -1; | ||||
|     } | ||||
| 
 | ||||
| @ -241,19 +248,37 @@ int inet_connect_opts(QemuOpts *opts) | ||||
|             continue; | ||||
|         } | ||||
|         setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); | ||||
| 
 | ||||
|         if (!block) { | ||||
|             socket_set_nonblock(sock); | ||||
|         } | ||||
|         /* connect to peer */ | ||||
|         if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { | ||||
|         do { | ||||
|             rc = 0; | ||||
|             if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) { | ||||
|                 rc = -socket_error(); | ||||
|             } | ||||
|         } while (rc == -EINTR); | ||||
| 
 | ||||
|   #ifdef _WIN32 | ||||
|         if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK | ||||
|                        || rc == -WSAEALREADY)) { | ||||
|   #else | ||||
|         if (!block && (rc == -EINPROGRESS)) { | ||||
|   #endif | ||||
|             error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS); | ||||
|         } else if (rc < 0) { | ||||
|             if (NULL == e->ai_next) | ||||
|                 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, | ||||
|                         inet_strfamily(e->ai_family), | ||||
|                         e->ai_canonname, uaddr, uport, strerror(errno)); | ||||
|             closesocket(sock); | ||||
|             sock = -1; | ||||
|             continue; | ||||
|         } | ||||
|         freeaddrinfo(res); | ||||
|         return sock; | ||||
|     } | ||||
|     error_set(errp, QERR_SOCKET_CONNECT_FAILED); | ||||
|     freeaddrinfo(res); | ||||
|     return -1; | ||||
| } | ||||
| @ -449,14 +474,20 @@ int inet_listen(const char *str, char *ostr, int olen, | ||||
|     return sock; | ||||
| } | ||||
| 
 | ||||
| int inet_connect(const char *str, int socktype) | ||||
| int inet_connect(const char *str, bool block, Error **errp) | ||||
| { | ||||
|     QemuOpts *opts; | ||||
|     int sock = -1; | ||||
| 
 | ||||
|     opts = qemu_opts_create(&dummy_opts, NULL, 0); | ||||
|     if (inet_parse(opts, str) == 0) | ||||
|         sock = inet_connect_opts(opts); | ||||
|     if (inet_parse(opts, str) == 0) { | ||||
|         if (block) { | ||||
|             qemu_opt_set(opts, "block", "on"); | ||||
|         } | ||||
|         sock = inet_connect_opts(opts, errp); | ||||
|     } else { | ||||
|         error_set(errp, QERR_SOCKET_CREATE_FAILED); | ||||
|     } | ||||
|     qemu_opts_del(opts); | ||||
|     return sock; | ||||
| } | ||||
|  | ||||
| @ -27,6 +27,8 @@ int inet_aton(const char *cp, struct in_addr *ia); | ||||
| #endif /* !_WIN32 */ | ||||
| 
 | ||||
| #include "qemu-option.h" | ||||
| #include "error.h" | ||||
| #include "qerror.h" | ||||
| 
 | ||||
| /* misc helpers */ | ||||
| int qemu_socket(int domain, int type, int protocol); | ||||
| @ -40,8 +42,8 @@ int send_all(int fd, const void *buf, int len1); | ||||
| int inet_listen_opts(QemuOpts *opts, int port_offset); | ||||
| int inet_listen(const char *str, char *ostr, int olen, | ||||
|                 int socktype, int port_offset); | ||||
| int inet_connect_opts(QemuOpts *opts); | ||||
| int inet_connect(const char *str, int socktype); | ||||
| int inet_connect_opts(QemuOpts *opts, Error **errp); | ||||
| int inet_connect(const char *str, bool block, Error **errp); | ||||
| int inet_dgram_opts(QemuOpts *opts); | ||||
| const char *inet_strfamily(int family); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								ui/vnc.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								ui/vnc.c
									
									
									
									
									
								
							| @ -3068,7 +3068,7 @@ int vnc_display_open(DisplayState *ds, const char *display) | ||||
|         if (strncmp(display, "unix:", 5) == 0) | ||||
|             vs->lsock = unix_connect(display+5); | ||||
|         else | ||||
|             vs->lsock = inet_connect(display, SOCK_STREAM); | ||||
|             vs->lsock = inet_connect(display, true, NULL); | ||||
|         if (-1 == vs->lsock) { | ||||
|             g_free(vs->display); | ||||
|             vs->display = NULL; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Amos Kong
						Amos Kong