/* * main entry pont of pcp worker child process */ void pcp_worker_main(int port) { sigjmp_buf local_sigjmp_buf; MemoryContext PCPMemoryContext; int authenticated = 0; char salt[4]; int random_salt = 0; struct timeval uptime; char tos; int rsize; char *buf = NULL; ereport(DEBUG1, (errmsg("I am PCP worker child with pid:%d",getpid()))); /* Identify myself via ps */ init_ps_display("", "", "", ""); gettimeofday(&uptime, NULL); srandom((unsigned int) (getpid() ^ uptime.tv_usec)); /* set up signal handlers */ signal(SIGTERM, die); signal(SIGINT, die); signal(SIGQUIT, die); signal(SIGCHLD, SIG_DFL); signal(SIGUSR2, wakeup_handler_child); signal(SIGUSR1, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGALRM, SIG_IGN); /* Create per loop iteration memory context */ PCPMemoryContext = AllocSetContextCreate(TopMemoryContext, "PCP_worker_main_loop", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(TopMemoryContext); /* * install the call back for preparation of pcp worker child exit */ on_system_exit(pcp_worker_will_go_down, (Datum)NULL); /* Initialize my backend status */ pool_initialize_private_backend_status(); /* Initialize process context */ pool_init_process_context(); pcp_frontend = pcp_open(port); unset_nonblock(pcp_frontend->fd); if (sigsetjmp(local_sigjmp_buf, 1) != 0) { error_context_stack = NULL; EmitErrorReport(); MemoryContextSwitchTo(TopMemoryContext); FlushErrorState(); } /* We can now handle ereport(ERROR) */ PG_exception_stack = &local_sigjmp_buf; for(;;) { MemoryContextSwitchTo(PCPMemoryContext); MemoryContextResetAndDeleteChildren(PCPMemoryContext); errno = 0; /* read a PCP packet */ do_pcp_read(pcp_frontend, &tos, 1); do_pcp_read(pcp_frontend, &rsize, sizeof(int)); rsize = ntohl(rsize); if ((rsize - sizeof(int)) > 0) { buf = (char *)palloc(rsize - sizeof(int)); do_pcp_read(pcp_frontend, buf, rsize - sizeof(int)); } ereport(DEBUG1, (errmsg("received PCP packet"), errdetail("PCP packet type of service '%c'", tos))); if (tos == 'R') /* authentication */ { set_ps_display("PCP: processing authentication", false); process_authentication(pcp_frontend, buf,salt, &random_salt); authenticated = 1; continue; } if (tos == 'M') /* md5 salt */ { set_ps_display("PCP: processing authentication", false); send_md5salt(pcp_frontend, salt); random_salt = 1; continue; } /* is this connection authenticated? if not disconnect immediately*/ if (!authenticated) ereport(FATAL, (errmsg("authentication failed for new PCP connection"), errdetail("connection not authorized"))); /* process a request */ pcp_process_command(tos, buf, rsize); } exit(0); }
/* -------------------------------- * pcp_connect - open connection to pgpool using given arguments * * return 0 on success, -1 otherwise * -------------------------------- */ int pcp_connect(char *hostname, int port, char *username, char *password) { struct sockaddr_in addr; struct sockaddr_un unix_addr; struct hostent *hp; int fd; int on = 1; int len; if (pc != NULL) { if (debug) fprintf(stderr, "DEBUG: connection to backend \"%s\" already exists\n", hostname); return 0; } if (hostname == NULL || *hostname == '\0' || *hostname == '/') { char *path; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { if (debug) fprintf(stderr, "DEBUG: could not create socket\n"); errorcode = SOCKERR; return -1; } memset(&unix_addr, 0, sizeof(unix_addr)); unix_addr.sun_family = AF_UNIX; if (hostname == NULL || *hostname == '\0') { path = UNIX_DOMAIN_PATH; } else { path = hostname; } snprintf(unix_addr.sun_path, sizeof(unix_addr.sun_path), "%s/.s.PGSQL.%d", path, port); if (connect(fd, (struct sockaddr *) &unix_addr, sizeof(unix_addr)) < 0) { if (debug) fprintf(stderr, "DEBUG: could not connect to \"%s\"\n", unix_addr.sun_path); close(fd); errorcode = CONNERR; return -1; } } else { fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { if (debug) fprintf(stderr, "DEBUG: could not create socket\n"); errorcode = SOCKERR; return -1; } if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { if (debug) fprintf(stderr, "DEBUG: could not set socket option\n"); close(fd); errorcode = SOCKERR; return -1; } memset((char *) &addr, 0, sizeof(addr)); addr.sin_family = AF_INET; hp = gethostbyname(hostname); if ((hp == NULL) || (hp->h_addrtype != AF_INET)) { if (debug) fprintf(stderr, "DEBUG: could not retrieve hostname\n"); close(fd); errorcode = HOSTERR; return -1; } memmove((char *) &(addr.sin_addr), (char *) hp->h_addr, hp->h_length); addr.sin_port = htons(port); len = sizeof(struct sockaddr_in); if (connect(fd, (struct sockaddr *) &addr, len) < 0) { if (debug) fprintf(stderr, "DEBUG: could not connect to \"%s\"\n", hostname); close(fd); errorcode = CONNERR; return -1; } } pc = pcp_open(fd); if (pc == NULL) { if (debug) fprintf(stderr, "DEBUG: could not allocate buffer space\n"); close(fd); return -1; } if (pcp_authorize(username, password) < 0) { pcp_close(pc); pc = NULL; return -1; } return 0; }
PCPConnInfo* pcp_connect(char *hostname, int port, char *username, char *password, FILE *Pfdebug) { struct sockaddr_in addr; struct sockaddr_un unix_addr; struct hostent *hp; char *password_fron_file = NULL; char os_user[256]; PCPConnInfo* pcpConn = palloc0(sizeof(PCPConnInfo)); int fd; int on = 1; int len; pcpConn->connState = PCP_CONNECTION_NOT_CONNECTED; pcpConn->Pfdebug = Pfdebug; if (hostname == NULL || *hostname == '\0' || *hostname == '/') { char *path; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { pcp_internal_error(pcpConn, "ERROR: failed to create UNIX domain socket. socket error \"%s\"",strerror(errno)); pcpConn->connState = PCP_CONNECTION_BAD; return pcpConn; } memset(&unix_addr, 0, sizeof(unix_addr)); unix_addr.sun_family = AF_UNIX; if (hostname == NULL || *hostname == '\0') { path = UNIX_DOMAIN_PATH; hostname = path; } else { path = hostname; } snprintf(unix_addr.sun_path, sizeof(unix_addr.sun_path), "%s/.s.PGSQL.%d", path, port); if (connect(fd, (struct sockaddr *) &unix_addr, sizeof(unix_addr)) < 0) { close(fd); pcp_internal_error(pcpConn, "ERROR: connection to socket \"%s\" failed with error \"%s\"",unix_addr.sun_path,strerror(errno)); pcpConn->connState = PCP_CONNECTION_BAD; return pcpConn; } } else { fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { pcp_internal_error(pcpConn, "ERROR: failed to create INET domain socket with error \"%s\"",strerror(errno)); pcpConn->connState = PCP_CONNECTION_BAD; return pcpConn; } if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { close(fd); pcp_internal_error(pcpConn, "ERROR: set socket option failed with error \"%s\"",strerror(errno)); pcpConn->connState = PCP_CONNECTION_BAD; return pcpConn; } memset((char *) &addr, 0, sizeof(addr)); addr.sin_family = AF_INET; hp = gethostbyname(hostname); if ((hp == NULL) || (hp->h_addrtype != AF_INET)) { close(fd); pcp_internal_error(pcpConn, "ERROR: could not retrieve hostname. gethostbyname failed with error \"%s\"",strerror(errno)); pcpConn->connState = PCP_CONNECTION_BAD; return pcpConn; } memmove((char *) &(addr.sin_addr), (char *) hp->h_addr, hp->h_length); addr.sin_port = htons(port); len = sizeof(struct sockaddr_in); if (connect(fd, (struct sockaddr *) &addr, len) < 0) { close(fd); pcp_internal_error(pcpConn, "ERROR: connection to host \"%s\" failed with error \"%s\"",hostname,strerror(errno)); pcpConn->connState = PCP_CONNECTION_BAD; return pcpConn; } } pcpConn->pcpConn = pcp_open(fd); if (pcpConn->pcpConn == NULL) { close(fd); pcp_internal_error(pcpConn, "ERROR: failed to allocate memory"); pcpConn->connState = PCP_CONNECTION_BAD; return pcpConn; } pcpConn->connState = PCP_CONNECTION_CONNECTED; /* * If username is not provided. Use the os user name * and do not complain if it (getting os user name) gets failed */ if (username == NULL && get_os_username(os_user, sizeof(os_user))) username = os_user; /* * If password is not provided. lookup in pcppass file */ if (password == NULL || *password == '\0') { char port_str[100]; snprintf(port_str, sizeof(port_str), "%d",port); password_fron_file = PasswordFromFile(pcpConn, hostname, port_str, username); password = password_fron_file; } if (pcp_authorize(pcpConn,username, password) < 0) { pcp_close(pcpConn->pcpConn); pcpConn->pcpConn = NULL; pcpConn->connState = PCP_CONNECTION_AUTH_ERROR; } else pcpConn->connState = PCP_CONNECTION_OK; if(password_fron_file) pfree(password_fron_file); return pcpConn; }