Ejemplo n.º 1
0
/*
 * A wrapper for getting one unix domain socket connection to server.
 *
 * sockpath[in]			The domain socket file name.
 * port[in] 			The port number.
 * clientfd[out]		The fd of connection.
 *
 * Return:
 * FUNC_RETURN_OK					Succeed.
 * UTIL_NETWORK_FAIL_CREATESOCKET. 	Fail to call socket().
 * UTIL_NETWORK_FAIL_BIND. 			Fail to call bind().
 * UTIL_NETWORK_FAIL_CONNECT. 		Fail to call connect().
 **/
int  connectToServerDomain(const char 	*sockpath,
						   uint16_t 	 port,
						   int 			*clientfd,
						   int			 fileidx,
						   char			*filename)
{
	struct sockaddr_un  sockaddr;
	int					fd			= 0;
	int					len			= 0;
	int					sockres		= 0;

	*clientfd   = -1;
	filename[0] = '\0';

	fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if ( fd < 0 )
	{
		write_log("Failed to open socket for connecting domain socket server "
				  "(errno %d)",
				  errno);
		return UTIL_NETWORK_FAIL_CREATESOCKET;
	}

	memset( &sockaddr, 0, sizeof(struct sockaddr_un) );
	sockaddr.sun_family = AF_UNIX;
	sprintf(sockaddr.sun_path, "%s.%d.%lu.%d",
			sockpath,
			getpid(),
			(unsigned long)pthread_self(),
			fileidx);
	len = offsetof(struct sockaddr_un, sun_path) + strlen(sockaddr.sun_path);
	unlink(sockaddr.sun_path);
	strcpy(filename, sockaddr.sun_path);

	sockres = bind(fd, (struct sockaddr *)&sockaddr, len);
	if ( sockres < 0 )
	{
		write_log("Failed to bind socket for connecting domain socket server "
				  "%s (errno %d), close fd %d at once",
				  filename,
				  errno,
				  fd);
		closeConnectionDomain(&fd, filename);
		return UTIL_NETWORK_FAIL_BIND;
	}

	memset( &sockaddr, 0, sizeof(struct sockaddr_un) );
	sockaddr.sun_family = AF_UNIX;
	sprintf(sockaddr.sun_path, "%s", sockpath);
	len = offsetof(struct sockaddr_un, sun_path) + strlen(sockaddr.sun_path);

	for ( int i = 0 ; i < DRM_SOCKET_CONN_RETRY ; ++i )
	{
		sockres = connect(fd, (struct sockaddr *)&sockaddr, len);
		if ( sockres < 0 )
		{
			write_log("Failed to connect to domain socket server "
					  "(retry %d, errno %d), fd %d",
					  i,
					  errno,
					  fd);
			pg_usleep(1000000); /* Sleep 1 seconds and retry. */
		}
		else
		{
			break;
		}
	}

	if ( sockres < 0 )
	{
		write_log("Failed to connect to domain socket server after retries, "
				  "close fd %d at once",
				  fd);
		closeConnectionDomain(&fd, filename);
		return UTIL_NETWORK_FAIL_CONNECT;
	}

	*clientfd = fd;
	return FUNC_RETURN_OK;
}
int callSyncRPCDomain(const char     	   *sockfile,
					  const char 	 	   *sendbuff,
		        	  int   		  		sendbuffsize,
					  uint16_t		  		sendmsgid,
					  uint16_t 		  		exprecvmsgid,
					  SelfMaintainBuffer 	recvsmb)
{
	static char            			dfilename[1024];
	int 							fd 			  = -1;
	int 							res 		  = FUNC_RETURN_OK;
	AsyncCommBuffer					newcommbuffer = NULL;
	AsyncCommMessageHandlerContext 	context 	  = NULL;
	SyncRPCContextData 				userdata;

	/* Connect to the server side. */
	res = connectToServerDomain(sockfile, 0, &fd, 0, dfilename);
	if ( res != FUNC_RETURN_OK )
	{
		elog(WARNING, "Fail to connect to domain socket server %s, result %d",
				  sockfile,
				  res);
		goto exit;
	}

	initializeSyncRPContent(&userdata, recvsmb, exprecvmsgid);
	context = createMessageHandlerContext(&userdata);

	res = registerFileDesc(fd,
						   dfilename,
						   ASYNCCOMM_READBYTES | ASYNCCOMM_WRITEBYTES,
						   &AsyncCommBufferHandlersMessage,
						   context,
						   &newcommbuffer);
	if ( res != FUNC_RETURN_OK )
	{
		rm_pfree(AsyncCommContext, context);
		elog(WARNING, "Fail to register FD for synchronous communication. %d", res);
		goto exit;
	}

	buildMessageToCommBuffer(newcommbuffer,
							 sendbuff,
							 sendbuffsize,
							 sendmsgid,
							 0,
							 0);
	context->AsyncBuffer = newcommbuffer;

	InitHandler_Message(newcommbuffer);

	/* Wait for the complete of the communication. */
	while( true )
	{
		processAllCommFileDescs();
		if ( userdata.CommStatus == SYNC_RPC_COMM_IDLE )
		{
			break;
		}
		else if ( QueryCancelPending )
		{
			/*
			 * We find that this QD wants to cancel the query, we don't need
			 * to continue the communication.
			 */
			res = TRANSCANCEL_INPROGRESS;
			break;
		}
	}

	res = res == TRANSCANCEL_INPROGRESS ? res : userdata.Result;

	/* Close and cleanup */
	closeAndRemoveAllRegisteredFileDesc();

	if (res != FUNC_RETURN_OK)
	{
	  elog(WARNING, "Sync RPC framework (domain) finds exception raised.");
	}
	return res;
exit:
	closeConnectionDomain(&fd, dfilename);
	return res;
}