int zbx_tcp_connect(zbx_sock_t *s, const char *source_ip, const char *ip, unsigned short port, int timeout) { ZBX_SOCKADDR servaddr_in, source_addr; struct hostent *hp; ZBX_TCP_START(); zbx_tcp_clean(s); if (NULL == (hp = gethostbyname(ip))) { #if defined(_WINDOWS) zbx_set_tcp_strerror("gethostbyname() failed for '%s': %s", ip, strerror_from_system(WSAGetLastError())); #elif defined(HAVE_HSTRERROR) zbx_set_tcp_strerror("gethostbyname() failed for '%s': [%d] %s", ip, h_errno, hstrerror(h_errno)); #else zbx_set_tcp_strerror("gethostbyname() failed for '%s': [%d]", ip, h_errno); #endif return FAIL; } servaddr_in.sin_family = AF_INET; servaddr_in.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr; servaddr_in.sin_port = htons(port); if (ZBX_SOCK_ERROR == (s->socket = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0))) { zbx_set_tcp_strerror("cannot create socket [[%s]:%d]: %s", ip, port, strerror_from_system(zbx_sock_last_error())); return FAIL; } #if !defined(_WINDOWS) && !SOCK_CLOEXEC fcntl(s->socket, F_SETFD, FD_CLOEXEC); #endif if (NULL != source_ip) { source_addr.sin_family = AF_INET; source_addr.sin_addr.s_addr = inet_addr(source_ip); source_addr.sin_port = 0; if (ZBX_TCP_ERROR == bind(s->socket, (struct sockaddr *)&source_addr, sizeof(source_addr))) { zbx_set_tcp_strerror("bind() failed: %s", strerror_from_system(zbx_sock_last_error())); return FAIL; } } if (0 != timeout) zbx_tcp_timeout_set(s, timeout); if (ZBX_TCP_ERROR == connect(s->socket, (struct sockaddr *)&servaddr_in, sizeof(servaddr_in))) { zbx_set_tcp_strerror("cannot connect to [[%s]:%d]: %s", ip, port, strerror_from_system(zbx_sock_last_error())); zbx_tcp_close(s); return FAIL; } return SUCCEED; }
int zbx_tcp_connect(zbx_sock_t *s, const char *source_ip, const char *ip, unsigned short port, int timeout) { ZBX_SOCKADDR servaddr_in, source_addr; struct hostent *hp; ZBX_TCP_START(); zbx_tcp_clean(s); if (NULL == (hp = zbx_gethost(ip))) return FAIL; servaddr_in.sin_family = AF_INET; servaddr_in.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr; servaddr_in.sin_port = htons(port); if (ZBX_SOCK_ERROR == (s->socket = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0))) { zbx_set_tcp_strerror("Cannot create socket [%s:%d] [%s]", ip, port, strerror_from_system(zbx_sock_last_error())); return FAIL; } #if !defined(_WINDOWS) && defined(HAVE_FCNTL_H) && !SOCK_CLOEXEC fcntl(s->socket, F_SETFD, FD_CLOEXEC); #endif if (NULL != source_ip) { source_addr.sin_family = AF_INET; source_addr.sin_addr.s_addr = inet_addr(source_ip); source_addr.sin_port = 0; if (ZBX_TCP_ERROR == bind(s->socket, (struct sockaddr *)&source_addr, sizeof(ZBX_SOCKADDR))) { zbx_set_tcp_strerror("bind() failed with error %d: %s\n", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); return FAIL; } } if (0 != timeout) zbx_tcp_timeout_set(s, timeout); if (ZBX_TCP_ERROR == connect(s->socket, (struct sockaddr *)&servaddr_in, sizeof(ZBX_SOCKADDR))) { zbx_set_tcp_strerror("Cannot connect to [%s:%d] [%s]", ip, port, strerror_from_system(zbx_sock_last_error())); zbx_tcp_close(s); return FAIL; } return SUCCEED; }
int zbx_tcp_send_ext(zbx_sock_t *s, const char *data, unsigned char flags, int timeout) { zbx_uint64_t len64; ssize_t i = 0, written = 0; int ret = SUCCEED; ZBX_TCP_START(); if (0 != timeout) zbx_tcp_timeout_set(s, timeout); if( flags & ZBX_TCP_NEW_PROTOCOL ) { /* Write header */ if( ZBX_TCP_ERROR == ZBX_TCP_WRITE(s->socket, ZBX_TCP_HEADER, ZBX_TCP_HEADER_LEN)) { zbx_set_tcp_strerror("ZBX_TCP_WRITE() failed [%s]", strerror_from_system(zbx_sock_last_error())); ret = FAIL; goto cleanup; } len64 = (zbx_uint64_t)strlen(data); len64 = zbx_htole_uint64(len64); /* Write data length */ if( ZBX_TCP_ERROR == ZBX_TCP_WRITE(s->socket, (char *) &len64, sizeof(len64)) ) { zbx_set_tcp_strerror("ZBX_TCP_WRITE() failed [%s]", strerror_from_system(zbx_sock_last_error())); ret = FAIL; goto cleanup; } } while(written < (ssize_t)strlen(data)) { if( ZBX_TCP_ERROR == (i = ZBX_TCP_WRITE(s->socket, data+written,(int)(strlen(data)-written))) ) { zbx_set_tcp_strerror("ZBX_TCP_WRITE() failed [%s]", strerror_from_system(zbx_sock_last_error())); ret = FAIL; goto cleanup; } written += i; } cleanup: if (0 != timeout) zbx_tcp_timeout_cleanup(s); return ret; }
/****************************************************************************** * * * Function: zbx_tcp_recv_ext * * * * Purpose: receive data * * * * Return value: number of bytes received - success, * * FAIL - an error occurred * * * * Author: Eugene Grigorjev * * * ******************************************************************************/ ssize_t zbx_tcp_recv_ext(zbx_sock_t *s, char **data, unsigned char flags, int timeout) { #define ZBX_BUF_LEN (ZBX_STAT_BUF_LEN * 8) ssize_t nbytes, left, total_bytes; size_t allocated, offset, read_bytes; zbx_uint64_t expected_len; ZBX_TCP_START(); if (0 != timeout) zbx_tcp_timeout_set(s, timeout); zbx_free(s->buf_dyn); total_bytes = 0; read_bytes = 0; s->buf_type = ZBX_BUF_TYPE_STAT; *data = s->buf_stat; left = ZBX_TCP_HEADER_LEN; if (ZBX_TCP_ERROR == (nbytes = ZBX_TCP_READ(s->socket, s->buf_stat, left))) goto out; if (ZBX_TCP_HEADER_LEN == nbytes && 0 == strncmp(s->buf_stat, ZBX_TCP_HEADER, ZBX_TCP_HEADER_LEN)) { total_bytes += nbytes; left = sizeof(zbx_uint64_t); if (left != (nbytes = ZBX_TCP_READ(s->socket, (void *)&expected_len, left))) { total_bytes = FAIL; goto out; } expected_len = zbx_letoh_uint64(expected_len); if (ZBX_MAX_RECV_DATA_SIZE < expected_len) { zabbix_log(LOG_LEVEL_WARNING, "Message size " ZBX_FS_UI64 " from %s" " exceeds the maximum size " ZBX_FS_UI64 " bytes. Message ignored.", expected_len, get_ip_by_socket(s), (zbx_uint64_t)ZBX_MAX_RECV_DATA_SIZE); total_bytes = FAIL; goto cleanup; } flags |= ZBX_TCP_READ_UNTIL_CLOSE; } else { read_bytes = nbytes; expected_len = 16 * ZBX_MEBIBYTE; } s->buf_stat[read_bytes] = '\0'; if (0 != (flags & ZBX_TCP_READ_UNTIL_CLOSE)) { if (0 == nbytes) goto cleanup; } else { if (nbytes < left) goto cleanup; } left = sizeof(s->buf_stat) - read_bytes - 1; /* check for an empty socket if exactly ZBX_TCP_HEADER_LEN bytes (without a header) were sent */ if (0 == read_bytes || '\n' != s->buf_stat[read_bytes - 1]) /* requests to passive agents end with '\n' */ { /* fill static buffer */ while (read_bytes < expected_len && 0 < left && ZBX_TCP_ERROR != (nbytes = ZBX_TCP_READ(s->socket, s->buf_stat + read_bytes, left))) { read_bytes += nbytes; if (0 != (flags & ZBX_TCP_READ_UNTIL_CLOSE)) { if (0 == nbytes) break; } else { if (nbytes < left) /* should we stop reading? */ { /* XML protocol? */ if (0 == strncmp(s->buf_stat, "<req>", sizeof("<req>") - 1)) { /* closing tag received in the last 10 bytes? */ s->buf_stat[read_bytes] = '\0'; if (NULL != strstr(s->buf_stat + read_bytes - (10 > read_bytes ? read_bytes : 10), "</req>")) break; } else break; } } left -= nbytes; } } s->buf_stat[read_bytes] = '\0'; if (sizeof(s->buf_stat) - 1 == read_bytes) /* static buffer is full */ { allocated = ZBX_BUF_LEN; s->buf_type = ZBX_BUF_TYPE_DYN; s->buf_dyn = zbx_malloc(s->buf_dyn, allocated); memcpy(s->buf_dyn, s->buf_stat, sizeof(s->buf_stat)); offset = read_bytes; /* fill dynamic buffer */ while (read_bytes < expected_len && ZBX_TCP_ERROR != (nbytes = ZBX_TCP_READ(s->socket, s->buf_stat, sizeof(s->buf_stat)))) { zbx_strncpy_alloc(&s->buf_dyn, &allocated, &offset, s->buf_stat, nbytes); read_bytes += nbytes; if (0 != (flags & ZBX_TCP_READ_UNTIL_CLOSE)) { if (0 == nbytes) break; } else { if ((size_t)nbytes < sizeof(s->buf_stat) - 1) /* should we stop reading? */ { /* XML protocol? */ if (0 == strncmp(s->buf_dyn, "<req>", sizeof("<req>") - 1)) { /* closing tag received in the last 10 bytes? */ if (NULL != strstr(s->buf_dyn + read_bytes - 10, "</req>")) break; } else break; } } } *data = s->buf_dyn; } out: if (ZBX_TCP_ERROR == nbytes) { zbx_set_tcp_strerror("ZBX_TCP_READ() failed: %s", strerror_from_system(zbx_sock_last_error())); total_bytes = FAIL; } cleanup: if (0 != timeout) zbx_tcp_timeout_cleanup(s); if (FAIL != total_bytes) total_bytes += read_bytes; return total_bytes; }
int zbx_tcp_connect(zbx_sock_t *s, const char *source_ip, const char *ip, unsigned short port, int timeout) { int ret = FAIL; struct addrinfo *ai = NULL, hints; struct addrinfo *ai_bind = NULL; char service[8]; ZBX_TCP_START(); zbx_tcp_clean(s); zbx_snprintf(service, sizeof(service), "%d", port); memset(&hints, 0x00, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (0 != getaddrinfo(ip, service, &hints, &ai)) { zbx_set_tcp_strerror("cannot resolve [%s]", ip); goto out; } if (ZBX_SOCK_ERROR == (s->socket = socket(ai->ai_family, ai->ai_socktype | SOCK_CLOEXEC, ai->ai_protocol))) { zbx_set_tcp_strerror("cannot create socket [[%s]:%d]: %s", ip, port, strerror_from_system(zbx_sock_last_error())); goto out; } #if !defined(_WINDOWS) && !SOCK_CLOEXEC fcntl(s->socket, F_SETFD, FD_CLOEXEC); #endif if (NULL != source_ip) { memset(&hints, 0x00, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST; if (0 != getaddrinfo(source_ip, NULL, &hints, &ai_bind)) { zbx_set_tcp_strerror("invalid source IP address [%s]", source_ip); goto out; } if (ZBX_TCP_ERROR == bind(s->socket, ai_bind->ai_addr, ai_bind->ai_addrlen)) { zbx_set_tcp_strerror("bind() failed: %s", strerror_from_system(zbx_sock_last_error())); goto out; } } if (0 != timeout) zbx_tcp_timeout_set(s, timeout); if (ZBX_TCP_ERROR == connect(s->socket, ai->ai_addr, ai->ai_addrlen)) { zbx_set_tcp_strerror("cannot connect to [[%s]:%d]: %s", ip, port, strerror_from_system(zbx_sock_last_error())); zbx_tcp_close(s); goto out; } ret = SUCCEED; out: if (NULL != ai) freeaddrinfo(ai); if (NULL != ai_bind) freeaddrinfo(ai_bind); return ret; }
/****************************************************************************** * * * Function: zbx_tcp_recv * * * * Purpose: receive data * * * * Parameters: * * * * Return value: SUCCEED - success * * FAIL - an error occurred * * * * Author: Eugene Grigorjev * * * * Comments: * * * ******************************************************************************/ int zbx_tcp_recv_ext(zbx_sock_t *s, char **data, unsigned char flags, int timeout) { #define ZBX_BUF_LEN ZBX_STAT_BUF_LEN*8 ssize_t nbytes, left; ssize_t read_bytes; int allocated, offset; int ret = SUCCEED; zbx_uint64_t expected_len; ZBX_TCP_START(); if (0 != timeout) zbx_tcp_timeout_set(s, timeout); zbx_free(s->buf_dyn); memset(s->buf_stat, 0, sizeof(s->buf_stat)); *data = s->buf_stat; read_bytes = 0; s->buf_type = ZBX_BUF_TYPE_STAT; left = ZBX_TCP_HEADER_LEN; nbytes = ZBX_TCP_READ(s->socket, s->buf_stat, left); if( ZBX_TCP_HEADER_LEN == nbytes && 0 == strncmp(s->buf_stat, ZBX_TCP_HEADER, ZBX_TCP_HEADER_LEN) ) { left = sizeof(zbx_uint64_t); nbytes = ZBX_TCP_READ(s->socket, (void *)&expected_len, left); expected_len = zbx_letoh_uint64(expected_len); /* The rest was already cleared */ memset(s->buf_stat, 0, ZBX_TCP_HEADER_LEN); flags |= ZBX_TCP_READ_UNTIL_CLOSE; } else if( ZBX_TCP_ERROR != nbytes ) { read_bytes = nbytes; expected_len = 16*1024*1024; } if( ZBX_TCP_ERROR != nbytes ) { if( flags & ZBX_TCP_READ_UNTIL_CLOSE ) { if(nbytes == 0) goto cleanup; } else { if(nbytes < left) goto cleanup; } left = sizeof(s->buf_stat) - read_bytes - 1; /* fill static buffer */ if ( s->buf_stat[ read_bytes - 1 ] != '\n' ) /* Don't try to read from an empty socket. */ { while( read_bytes < expected_len && left > 0 && ZBX_TCP_ERROR != (nbytes = ZBX_TCP_READ( s->socket, s->buf_stat + read_bytes, left))) { read_bytes += nbytes; if( flags & ZBX_TCP_READ_UNTIL_CLOSE ) { if(nbytes == 0) break; } else { if(nbytes < left) break; } left -= nbytes; } } s->buf_stat[read_bytes] = '\0'; if( (sizeof(s->buf_stat) - 1) == read_bytes) /* static buffer is full */ { allocated = ZBX_BUF_LEN; s->buf_type = ZBX_BUF_TYPE_DYN; s->buf_dyn = zbx_malloc(s->buf_dyn, allocated); memset(s->buf_dyn, 0, allocated); memcpy(s->buf_dyn, s->buf_stat, sizeof(s->buf_stat)); offset = read_bytes; /* fill dynamic buffer */ while( read_bytes < expected_len && ZBX_TCP_ERROR != (nbytes = ZBX_TCP_READ(s->socket, s->buf_stat, sizeof(s->buf_stat)-1)) ) { s->buf_stat[nbytes] = '\0'; zbx_snprintf_alloc(&(s->buf_dyn), &allocated, &offset, sizeof(s->buf_stat), "%s", s->buf_stat); read_bytes += nbytes; if( flags & ZBX_TCP_READ_UNTIL_CLOSE ) { if(nbytes == 0) break; } else { if(nbytes < sizeof(s->buf_stat) - 1) break; } } *data = s->buf_dyn; } } if( ZBX_TCP_ERROR == nbytes ) { zbx_set_tcp_strerror("ZBX_TCP_READ() failed [%s]", strerror_from_system(zbx_sock_last_error())); ret = FAIL; } cleanup: if (0 != timeout) zbx_tcp_timeout_cleanup(s); return ret; }