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_listen( zbx_sock_t *s, const char *listen_ip, unsigned short listen_port ) { ZBX_SOCKADDR serv_addr; int on, res = FAIL; ZBX_TCP_START(); zbx_tcp_clean(s); if(ZBX_SOCK_ERROR == (s->socket = socket(AF_INET,SOCK_STREAM,0))) { zbx_set_tcp_strerror("Cannot create socket [%s:%u] [%s]", listen_ip, listen_port, strerror_from_system(zbx_sock_last_error())); goto out; } /* Enable address reuse */ /* This is to immediately use the address even if it is in TIME_WAIT state */ /* http://www-128.ibm.com/developerworks/linux/library/l-sockpit/index.html */ on = 1; if( -1 == setsockopt(s->socket, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on) )) { zbx_set_tcp_strerror("Cannot setsockopt SO_REUSEADDR [%s]", strerror_from_system(zbx_sock_last_error())); } /* Create socket Fill in local address structure */ memset(&serv_addr, 0, sizeof(ZBX_SOCKADDR)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = listen_ip ? inet_addr(listen_ip) : htonl(INADDR_ANY); serv_addr.sin_port = htons((unsigned short)listen_port); /* Bind socket */ if (ZBX_SOCK_ERROR == bind(s->socket,(struct sockaddr *)&serv_addr,sizeof(ZBX_SOCKADDR)) ) { zbx_set_tcp_strerror("Cannot bind to port %u for server %s. Error [%s]. Another zabbix_agentd already running ?", listen_port, listen_ip ? listen_ip : "[ANY]", strerror_from_system(zbx_sock_last_error())); goto out; } if( ZBX_SOCK_ERROR == listen(s->socket, SOMAXCONN) ) { zbx_set_tcp_strerror("Listen failed. [%s]", strerror_from_system(zbx_sock_last_error())); goto out; } res = SUCCEED; out: return res; }
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_listen(zbx_sock_t *s, const char *listen_ip, unsigned short listen_port) { ZBX_SOCKADDR serv_addr; char *ip, *ips, *delim; int i, on, ret = FAIL; ZBX_TCP_START(); zbx_tcp_clean(s); ip = ips = (NULL == listen_ip ? NULL : strdup(listen_ip)); while (1) { delim = (NULL == ip ? NULL : strchr(ip, ',')); if (NULL != delim) *delim = '\0'; if (NULL != ip && FAIL == is_ip4(ip)) { zbx_set_tcp_strerror("incorrect IPv4 address [%s]", ip); goto out; } if (ZBX_SOCKET_COUNT == s->num_socks) { zbx_set_tcp_strerror("not enough space for socket [[%s]:%hu]", ip ? ip : "-", listen_port); goto out; } if (ZBX_SOCK_ERROR == (s->sockets[s->num_socks] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0))) { zbx_set_tcp_strerror("socket() for [[%s]:%hu] failed: %s", ip ? ip : "-", listen_port, strerror_from_system(zbx_sock_last_error())); goto out; } #if !defined(_WINDOWS) && !SOCK_CLOEXEC fcntl(s->sockets[s->num_socks], F_SETFD, FD_CLOEXEC); #endif /* Enable address reuse */ /* This is to immediately use the address even if it is in TIME_WAIT state */ /* http://www-128.ibm.com/developerworks/linux/library/l-sockpit/index.html */ on = 1; if (ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on))) { zbx_set_tcp_strerror("setsockopt() for [[%s]:%hu] failed: %s", ip ? ip : "-", listen_port, strerror_from_system(zbx_sock_last_error())); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = NULL != ip ? inet_addr(ip) : htonl(INADDR_ANY); serv_addr.sin_port = htons((unsigned short)listen_port); if (ZBX_TCP_ERROR == bind(s->sockets[s->num_socks], (struct sockaddr *)&serv_addr, sizeof(serv_addr))) { zbx_set_tcp_strerror("bind() for [[%s]:%hu] failed: %s", ip ? ip : "-", listen_port, strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); goto out; } if (ZBX_TCP_ERROR == listen(s->sockets[s->num_socks], SOMAXCONN)) { zbx_set_tcp_strerror("listen() for [[%s]:%hu] failed: %s", ip ? ip : "-", listen_port, strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); goto out; } s->num_socks++; if (NULL == ip || NULL == delim) break; *delim = ','; ip = delim + 1; } if (0 == s->num_socks) { zbx_set_tcp_strerror("zbx_tcp_listen() fatal error: unable to serve on any address [[%s]:%hu]", listen_ip ? listen_ip : "-", listen_port); goto out; } ret = SUCCEED; out: if (NULL != ips) zbx_free(ips); if (SUCCEED != ret) { for (i = 0; i < s->num_socks; i++) zbx_sock_close(s->sockets[i]); } return ret; }
int zbx_tcp_listen(zbx_sock_t *s, const char *listen_ip, unsigned short listen_port) { struct addrinfo hints, *ai = NULL, *current_ai; char port[8], *ip, *ips, *delim; int i, err, on, ret = FAIL; ZBX_TCP_START(); zbx_tcp_clean(s); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; zbx_snprintf(port, sizeof(port), "%hu", listen_port); ip = ips = (NULL == listen_ip ? NULL : strdup(listen_ip)); while (1) { delim = (NULL == ip ? NULL : strchr(ip, ',')); if (NULL != delim) *delim = '\0'; if (0 != (err = getaddrinfo(ip, port, &hints, &ai))) { zbx_set_tcp_strerror("cannot resolve address [[%s]:%s]: [%d] %s", ip ? ip : "-", port, err, gai_strerror(err)); goto out; } for (current_ai = ai; NULL != current_ai; current_ai = current_ai->ai_next) { if (ZBX_SOCKET_COUNT == s->num_socks) { zbx_set_tcp_strerror("not enough space for socket [[%s]:%s]", ip ? ip : "-", port); goto out; } if (PF_INET != current_ai->ai_family && PF_INET6 != current_ai->ai_family) continue; if (ZBX_SOCK_ERROR == (s->sockets[s->num_socks] = socket(current_ai->ai_family, current_ai->ai_socktype | SOCK_CLOEXEC, current_ai->ai_protocol))) { zbx_set_tcp_strerror("socket() for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); #ifdef _WINDOWS if (WSAEAFNOSUPPORT == zbx_sock_last_error()) #else if (EAFNOSUPPORT == zbx_sock_last_error()) #endif continue; else goto out; } #if !defined(_WINDOWS) && !SOCK_CLOEXEC fcntl(s->sockets[s->num_socks], F_SETFD, FD_CLOEXEC); #endif /* enable address reuse */ /* this is to immediately use the address even if it is in TIME_WAIT state */ /* http://www-128.ibm.com/developerworks/linux/library/l-sockpit/index.html */ on = 1; if (ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on))) { zbx_set_tcp_strerror("setsockopt() with SO_REUSEADDR for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); } #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if (PF_INET6 == current_ai->ai_family && ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on))) { zbx_set_tcp_strerror("setsockopt() with IPV6_V6ONLY for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); } #endif if (ZBX_TCP_ERROR == bind(s->sockets[s->num_socks], current_ai->ai_addr, current_ai->ai_addrlen)) { zbx_set_tcp_strerror("bind() for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); #ifdef _WINDOWS if (WSAEADDRINUSE == zbx_sock_last_error()) #else if (EADDRINUSE == zbx_sock_last_error()) #endif continue; else goto out; } if (ZBX_TCP_ERROR == listen(s->sockets[s->num_socks], SOMAXCONN)) { zbx_set_tcp_strerror("listen() for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); goto out; } s->num_socks++; } if (NULL != ai) { freeaddrinfo(ai); ai = NULL; } if (NULL == ip || NULL == delim) break; *delim = ','; ip = delim + 1; } if (0 == s->num_socks) { zbx_set_tcp_strerror("zbx_tcp_listen() fatal error: unable to serve on any address [[%s]:%hu]", listen_ip ? listen_ip : "-", listen_port); goto out; } ret = SUCCEED; out: if (NULL != ips) zbx_free(ips); if (NULL != ai) freeaddrinfo(ai); if (SUCCEED != ret) { for (i = 0; i < s->num_socks; i++) zbx_sock_close(s->sockets[i]); } return ret; }
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; }
int zbx_tcp_listen( zbx_sock_t *s, const char *listen_ip, unsigned short listen_port ) { struct addrinfo hints, *ai = NULL, *current_ai; char port[MAX_STRING_LEN]; int e, on, ret = FAIL; ZBX_TCP_START(); zbx_tcp_clean(s); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; zbx_snprintf(port, sizeof(port), "%d", listen_port); if(0 != (e = getaddrinfo(listen_ip, port, &hints, &ai))) { zbx_set_tcp_strerror("Cannot resolve address [[%s]:%u], error %d: %s", listen_ip, listen_port, e, gai_strerror(e)); goto out; } for(s->num_socks = 0, current_ai = ai; current_ai != NULL; current_ai = current_ai->ai_next) { if(s->num_socks == FD_SETSIZE) { break; } /* This example only supports PF_INET and PF_INET6. */ if((current_ai->ai_family != PF_INET) && (current_ai->ai_family != PF_INET6)) continue; if((s->sockets[s->num_socks] = socket(current_ai->ai_family, current_ai->ai_socktype, current_ai->ai_protocol)) == ZBX_SOCK_ERROR) { zbx_set_tcp_strerror("socket() failed with error %d: %s", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); continue; } /* Enable address reuse */ /* This is to immediately use the address even if it is in TIME_WAIT state */ /* http://www-128.ibm.com/developerworks/linux/library/l-sockpit/index.html */ on = 1; if(setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)) == ZBX_TCP_ERROR) { zbx_set_tcp_strerror("setsockopt() failed with error %d: %s", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); } /* Create socket Fill in local address structure */ if(bind(s->sockets[s->num_socks], current_ai->ai_addr, current_ai->ai_addrlen) == ZBX_TCP_ERROR) { zbx_set_tcp_strerror("bind() failed with error %d: %s", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); continue; } if(ZBX_SOCK_ERROR == listen(s->sockets[s->num_socks], SOMAXCONN) ) { zbx_set_tcp_strerror("listen() failed with error %d: %s", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); continue; } s->num_socks++; } if(s->num_socks == 0) { zbx_set_tcp_strerror("zbx_tcp_listen() Fatal error: unable to serve on any address. [[%s]:%u]", listen_ip, listen_port); goto out; } ret = SUCCEED; out: if (NULL != ai) freeaddrinfo(ai); return ret; }
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))) { zbx_set_tcp_strerror("Cannot resolve [%s]", 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,0))) { zbx_set_tcp_strerror("Cannot create socket [%s:%d] [%s]", ip, port ,strerror_from_system(zbx_sock_last_error())); return FAIL; } 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_SOCK_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) { s->timeout = timeout; #if defined(_WINDOWS) timeout *= 1000; if (setsockopt(s->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)) == ZBX_TCP_ERROR) zbx_set_tcp_strerror("setsockopt() failed with error %d: %s", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); if (setsockopt(s->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout)) == ZBX_TCP_ERROR) zbx_set_tcp_strerror("setsockopt() failed with error %d: %s", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); #else alarm(timeout); #endif } 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_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[MAX_STRING_LEN]; 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, 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 (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]\n", 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 with error %d: %s\n", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); goto out; } } if (0 != timeout) { s->timeout = timeout; #if defined(_WINDOWS) timeout *= 1000; if (setsockopt(s->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)) == ZBX_TCP_ERROR) zbx_set_tcp_strerror("setsockopt() failed with error %d: %s", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); if (setsockopt(s->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout)) == ZBX_TCP_ERROR) zbx_set_tcp_strerror("setsockopt() failed with error %d: %s", zbx_sock_last_error(), strerror_from_system(zbx_sock_last_error())); #else alarm(timeout); #endif } 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; }