int upscli_connect(UPSCONN *ups, const char *host, int port, int flags) { struct sockaddr_in local, server; struct hostent *serv; unsigned long numericIPAddr=INADDR_NONE; /* clear out any lingering junk */ ups->fd = INVALID_SOCKET; ups->host = NULL; ups->flags = 0; ups->upserror = 0; ups->syserrno = 0; ups->upsclient_magic = UPSCLIENT_MAGIC; ups->pc_ctx = malloc(sizeof(PCONF_CTX)); if (!ups->pc_ctx) { ups->upserror = UPSCLI_ERR_NOMEM; return -1; } pconf_init(ups->pc_ctx, NULL); ups->ssl_ctx = NULL; ups->ssl = NULL; if (!host) { ups->upserror = UPSCLI_ERR_NOSUCHHOST; return -1; } memset(&local, '\0', sizeof(struct sockaddr_in)); local.sin_family = AF_INET; local.sin_port = htons(INADDR_ANY); memset(&server, '\0', sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons((u_short)port); //Windows is brain dead when it comes to gethostbyname and numeric ip addresses. GRRrrrr numericIPAddr = inet_addr(host); if(numericIPAddr != INADDR_NONE) { /* the string is a numeric IP address, just set it on the server addr struct */ server.sin_addr.s_addr = numericIPAddr; } else if((serv = gethostbyname(host)) != (struct hostent *) NULL) { /* the string is a DNS name, we resolved and stored it to the serv structure so now set it on the server struct */ memcpy (&server.sin_addr, serv->h_addr, serv->h_length); } else /* could not resolve name or IP */ { ups->upserror = UPSCLI_ERR_NOSUCHHOST; ups->syserrno = errno = WSAGetLastError(); return (-1); } if ((ups->fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { ups->upserror = UPSCLI_ERR_SOCKFAILURE; ups->syserrno = errno = WSAGetLastError(); return -1; } if (bind(ups->fd, (struct sockaddr *) &local, sizeof(struct sockaddr_in)) == -1) { ups->upserror = UPSCLI_ERR_BINDFAILURE; ups->syserrno = errno; close(ups->fd); ups->fd = INVALID_SOCKET; return -1; } if (connect(ups->fd, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) == -1) { ups->upserror = UPSCLI_ERR_CONNFAILURE; ups->syserrno = errno; close(ups->fd); ups->fd = INVALID_SOCKET; return -1; } /* don't use xstrdup for cleaner linking (fewer dependencies) */ ups->host = strdup(host); if (!ups->host) { close(ups->fd); ups->fd = INVALID_SOCKET; ups->upserror = UPSCLI_ERR_NOMEM; return -1; } ups->port = port; if (flags & UPSCLI_CONN_TRYSSL) { upscli_sslinit(ups); /* see if something made us die inside sslinit */ if (ups->upserror != 0) return -1; } if (flags & UPSCLI_CONN_REQSSL) { if (upscli_sslinit(ups) != 1) { ups->upserror = UPSCLI_ERR_SSLFAIL; upscli_closefd(ups); return -1; } } return 0; }
int upscli_tryconnect(UPSCONN_t *ups, const char *host, int port, int flags,struct timeval * timeout) { int sock_fd; struct addrinfo hints, *res, *ai; char sport[NI_MAXSERV]; int v; fd_set wfds; int error; socklen_t error_size; long fd_flags; if (!ups) { return -1; } /* clear out any lingering junk */ memset(ups, 0, sizeof(*ups)); ups->upsclient_magic = UPSCLIENT_MAGIC; ups->fd = -1; if (!host) { ups->upserror = UPSCLI_ERR_NOSUCHHOST; return -1; } snprintf(sport, sizeof(sport), "%hu", (unsigned short int)port); memset(&hints, 0, sizeof(hints)); if (flags & UPSCLI_CONN_INET6) { hints.ai_family = AF_INET6; } else if (flags & UPSCLI_CONN_INET) { hints.ai_family = AF_INET; } else { hints.ai_family = AF_UNSPEC; } hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; while ((v = getaddrinfo(host, sport, &hints, &res)) != 0) { switch (v) { case EAI_AGAIN: continue; case EAI_NONAME: ups->upserror = UPSCLI_ERR_NOSUCHHOST; return -1; case EAI_MEMORY: ups->upserror = UPSCLI_ERR_NOMEM; return -1; case EAI_SYSTEM: ups->syserrno = errno; break; } ups->upserror = UPSCLI_ERR_UNKNOWN; return -1; } for (ai = res; ai != NULL; ai = ai->ai_next) { sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock_fd < 0) { switch (errno) { case EAFNOSUPPORT: case EINVAL: break; default: ups->upserror = UPSCLI_ERR_SOCKFAILURE; ups->syserrno = errno; } continue; } /* non blocking connect */ if(timeout != NULL) { fd_flags = fcntl(sock_fd, F_GETFL); fd_flags |= O_NONBLOCK; fcntl(sock_fd, F_SETFL, fd_flags); } while ((v = connect(sock_fd, ai->ai_addr, ai->ai_addrlen)) < 0) { if(errno == EINPROGRESS) { FD_ZERO(&wfds); FD_SET(sock_fd, &wfds); select(sock_fd+1,NULL,&wfds,NULL, timeout); if (FD_ISSET(sock_fd, &wfds)) { error_size = sizeof(error); getsockopt(sock_fd,SOL_SOCKET,SO_ERROR, &error,&error_size); if( error == 0) { /* connect successful */ v = 0; break; } errno = error; } else { /* Timeout */ v = -1; break; } } switch (errno) { case EAFNOSUPPORT: break; case EINTR: case EAGAIN: continue; default: ups->upserror = UPSCLI_ERR_CONNFAILURE; ups->syserrno = errno; } break; } if (v < 0) { close(sock_fd); continue; } /* switch back to blocking operation */ if(timeout != NULL) { fd_flags = fcntl(sock_fd, F_GETFL); fd_flags &= ~O_NONBLOCK; fcntl(sock_fd, F_SETFL, fd_flags); } ups->fd = sock_fd; ups->upserror = 0; ups->syserrno = 0; break; } freeaddrinfo(res); if (ups->fd < 0) { return -1; } pconf_init(&ups->pc_ctx, NULL); ups->host = strdup(host); if (!ups->host) { ups->upserror = UPSCLI_ERR_NOMEM; upscli_disconnect(ups); return -1; } ups->port = port; if (flags & UPSCLI_CONN_TRYSSL) { upscli_sslinit(ups); /* see if something made us die inside sslinit */ if (ups->upserror != 0) { upscli_disconnect(ups); return -1; } } if ((flags & UPSCLI_CONN_REQSSL) && (upscli_sslinit(ups) != 1)) { ups->upserror = UPSCLI_ERR_SSLFAIL; upscli_disconnect(ups); return -1; } return 0; }