| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <sys/epoll.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <sys/un.h> |
| #include <netdb.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/select.h> |
| #include <signal.h> |
| #include <sys/time.h> |
| |
| #include "mbtk_sock.h" |
| #include "mbtk_log.h" |
| |
| int sock_net_open(mbtk_net_info_s *net_info, mbtk_addr_family_e addr_family) |
| { |
| return 0; |
| } |
| |
| int sock_open(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, uint32 timeout, int *err) |
| { |
| if(net_info == NULL || sock_info == NULL) { |
| LOGE("ARG error."); |
| return -1; |
| } |
| int family = AF_INET; |
| if(sock_info->addr_family == MBTK_ADDR_IPV6) { // Only IPv6 |
| family = AF_INET6; |
| } |
| if(sock_info->sock_type == MBTK_SOCK_UDP_COM) { // UDP |
| // socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| if((sock_info->fd = socket(family, SOCK_DGRAM, IPPROTO_UDP)) < 0){ |
| LOGE("socket() fail.[%d]",errno); |
| goto result_fail; |
| } |
| } else if(sock_info->sock_type == MBTK_SOCK_TCP_COM){ // TCP |
| if((sock_info->fd = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0){ |
| LOGE("socket() fail.[%d]",errno); |
| goto result_fail; |
| } |
| } else { |
| LOGE("Unknown socket type:%d", sock_info->sock_type); |
| return -1; |
| } |
| #if 1 |
| // Set O_NONBLOCK |
| int flags = fcntl(sock_info->fd, F_GETFL, 0); |
| if (flags < 0) { |
| LOGE("Get flags error:%d", errno); |
| goto result_fail_with_close; |
| } |
| flags |= O_NONBLOCK; |
| if (fcntl(sock_info->fd, F_SETFL, flags) < 0) { |
| LOGE("Set flags error:%d", errno); |
| goto result_fail_with_close; |
| } |
| #endif |
| // Connect |
| LOGD("Start conn:%s:%d",sock_info->host,sock_info->port); |
| if (strlen(sock_info->host) > 0 && sock_info->port > 0) |
| { |
| if(family == AF_INET6) |
| { |
| struct addrinfo hints; |
| struct addrinfo *answer, *curr; |
| memset(&hints, 0, sizeof(struct addrinfo)); |
| hints.ai_family = AF_INET6; /* Allow IPv4 or IPv6 */ |
| hints.ai_socktype = sock_info->sock_type; /* Datagram socket */ |
| hints.ai_flags = 0; |
| hints.ai_protocol = 0; /* Any protocol */ |
| |
| int ret = getaddrinfo(sock_info->host, NULL, &hints, &answer); |
| if(ret < 0) |
| { |
| printf("\ngetaddrinfo error\n"); |
| goto result_fail_with_close; |
| } |
| |
| struct sockaddr_in6 *addr_in6=NULL; |
| struct sockaddr_in6 serverSockAddr; |
| bzero(&serverSockAddr, sizeof(struct sockaddr_in6)); |
| serverSockAddr.sin6_family = AF_INET6; |
| serverSockAddr.sin6_port = htons(sock_info->port); |
| //memcpy(&serverSockAddr.sin6_addr, he->h_addr_list[0], sizeof(struct in6_addr)); |
| //memcpy(&sock_info->addr.addr.dst_sock_addr6.sin6_addr, he->h_addr_list[0], sizeof(struct in_addr)); |
| sock_info->addr.addr_len = sizeof(struct sockaddr_in6); |
| |
| for (curr = answer; curr != NULL; curr = curr->ai_next) |
| { |
| addr_in6 = (struct sockaddr_in6 *)curr->ai_addr; |
| memcpy(&(serverSockAddr.sin6_addr), &(addr_in6->sin6_addr), sizeof(struct in6_addr)); |
| } |
| if (connect(sock_info->fd, (struct sockaddr*)&serverSockAddr, sizeof(struct sockaddr_in6)) < 0) |
| { |
| if (EINPROGRESS != errno) |
| { |
| LOGE("connect() fail.[%d]", errno); |
| goto result_fail_with_close; |
| } |
| } |
| } |
| else |
| { |
| struct hostent *he = gethostbyname(sock_info->host); |
| if (he == NULL) |
| { |
| LOGE("gethostbyname() fail.[%d]", errno); |
| goto result_fail_with_close; |
| } |
| struct sockaddr_in serverSockAddr; |
| bzero(&serverSockAddr, sizeof(struct sockaddr_in)); |
| serverSockAddr.sin_family = AF_INET; |
| serverSockAddr.sin_port = htons(sock_info->port); |
| memcpy(&serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr)); |
| |
| log_hex("IPv4", he->h_addr_list[0], sizeof(struct in_addr)); |
| |
| memcpy(&sock_info->addr.addr.serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr)); |
| sock_info->addr.addr_len = sizeof(struct sockaddr_in); |
| if (connect(sock_info->fd, (struct sockaddr *) &serverSockAddr, sizeof(serverSockAddr)) < 0) |
| { |
| if (EINPROGRESS != errno) |
| { |
| LOGE("connect() fail.[%d]", errno); |
| goto result_fail_with_close; |
| } |
| } |
| } |
| |
| fd_set rset, wset; |
| FD_ZERO(&rset); |
| FD_ZERO(&wset); |
| FD_SET(sock_info->fd, &rset); |
| FD_SET(sock_info->fd, &wset); |
| struct timeval time_out; |
| /* |
| time_out.tv_sec = timeout / 1000; |
| time_out.tv_usec = timeout % 1000 * 1000; |
| */ |
| time_out.tv_sec = 100; |
| time_out.tv_usec = 0; |
| int nready = select(sock_info->fd + 1, &rset, &wset, NULL, &time_out); |
| LOGD("nready = %d", nready); |
| if (nready == 0) // Timeout |
| { |
| LOGE("Timeout."); |
| goto result_fail_with_close; |
| } |
| else |
| { |
| if (FD_ISSET(sock_info->fd, &rset) && FD_ISSET(sock_info->fd, &wset)) |
| { |
| int error = -1; |
| socklen_t len = sizeof(int); |
| LOGE("Can read and write."); |
| if (getsockopt(sock_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) |
| { |
| LOGE("getsockopt fail.[%d]", errno); |
| goto result_fail_with_close; |
| } |
| else |
| { |
| LOGE("error = %d", error); |
| if (error != 0) // Fail |
| { |
| goto result_fail_with_close; |
| } |
| } |
| } |
| else if (FD_ISSET(sock_info->fd, &wset)) |
| { |
| LOGI("Can write."); |
| } |
| else |
| { |
| LOGE("Can read(Impossible)."); |
| goto result_fail_with_close; |
| } |
| } |
| } |
| else |
| { |
| LOGE("Can not conn."); |
| goto result_fail_with_close; |
| } |
| |
| if (sock_info->is_ssl) |
| { |
| |
| } |
| |
| sock_info->read_buff.buffer = (char*)malloc(MBTK_BUFF_SIZE); |
| if(sock_info->read_buff.buffer) { |
| memset(sock_info->read_buff.buffer, 0x0, MBTK_BUFF_SIZE); |
| sock_info->read_buff.size = 0; |
| sock_info->read_buff.size_max = MBTK_BUFF_SIZE; |
| } else { |
| LOGE("malloc() fail."); |
| goto result_fail_with_close; |
| } |
| |
| return sock_info->fd; |
| result_fail_with_close: |
| close(sock_info->fd); |
| sock_info->fd = -1; |
| result_fail: |
| LOGE("mbtk_sock_open() end:fail"); |
| return -1; |
| } |
| |
| int sock_addr_set(mbtk_net_info_s *net_info,mbtk_sock_info_s *sock_info,void *host, uint32 port) |
| { |
| if(sock_info->fd <= 0) { |
| LOGE("Socket not open."); |
| return -1; |
| } |
| |
| sock_info->addr.addr.serverSockAddr.sin_family = AF_INET; |
| sock_info->addr.addr.serverSockAddr.sin_port = htons(port); |
| struct hostent *he = gethostbyname(host); |
| if (he == NULL) |
| { |
| LOGE("gethostbyname() fail.[%d]", errno); |
| return -1; |
| } |
| else |
| { |
| LOGD("Ip(len-%d)", he->h_length); |
| int i = 0; |
| for(;i < he->h_length;i++){ |
| LOGD("Ip Addr[%d]:%.2x", i, 0x0FF & he->h_addr_list[0][i]); |
| } |
| } |
| memcpy(&sock_info->addr.addr.serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr)); |
| sock_info->addr.addr_len = sizeof(struct sockaddr_in); |
| |
| return 0; |
| } |
| |
| int sock_bind(int sockfd, bool is_ipv6, uint16 port) |
| { |
| int ret_val; |
| struct sockaddr *ds_sockaddr = NULL; |
| struct sockaddr_in localaddr; |
| uint16 addr_legth = 0; |
| |
| memset((char *) &localaddr, 0, sizeof(struct sockaddr_in)); |
| localaddr.sin_family = AF_INET; |
| localaddr.sin_addr.s_addr = INADDR_ANY; |
| localaddr.sin_port = htons(port); |
| addr_legth = sizeof(struct sockaddr_in); |
| ds_sockaddr = (struct sockaddr *)&localaddr; |
| ret_val = bind(sockfd,ds_sockaddr,addr_legth); |
| if (ret_val < 0){ |
| LOGE("bind() sockfd= %d fail", sockfd); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int sock_read(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err) |
| { |
| unsigned int count = 0; |
| int len = 0; |
| int try_count = 0; |
| int times = timeout / 50; |
| memset(buffer, 0x0, buf_len); |
| while (count < buf_len) |
| { |
| try_count++; |
| if (sock_info->is_ssl) |
| { |
| |
| } |
| else |
| { |
| len = read(sock_info->fd, (char*) buffer + count, buf_len - count); |
| } |
| if (len <= 0) |
| { |
| if (errno == EWOULDBLOCK || errno == EAGAIN) |
| { |
| if (count > 0) // Read data |
| break; // Read data end. |
| |
| if (try_count >= times) // Timeout |
| { |
| count = -1; |
| if (times != 0) |
| { |
| *err = 10; // FTP_ERR_NET_TIMEOUT |
| } |
| LOGE("Not read enough data,return.[%d/%d]", count, buf_len); |
| break; |
| } |
| else |
| { |
| usleep(50000); |
| continue; |
| } |
| } |
| else |
| { |
| LOGD("read error.[%d]", errno); |
| if (errno == EINPROGRESS) |
| { |
| if (close(sock_info->fd) == 0) // Success |
| { |
| LOGD("Socket disconnected.Close it."); |
| sock_info->fd = -1; |
| } |
| if (count <= 0) |
| count = -1; |
| } |
| else |
| { |
| if (count <= 0) |
| count = 0; |
| } |
| break; |
| } |
| } |
| else |
| { |
| count += len; |
| } |
| } |
| |
| LOGV("Read data[%d/%d].", count, buf_len); |
| |
| return count; |
| } |
| |
| int sock_read_async(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err) |
| { |
| int len = -1; |
| int try_count = 0; |
| int times = timeout / 50; |
| |
| TCP_READ_AGAIN: |
| memset(buffer, 0x0, buf_len); |
| try_count++; |
| if (sock_info->is_ssl) |
| { |
| |
| } |
| else |
| { |
| len = read(sock_info->fd, (char*) buffer, buf_len); |
| } |
| if (len < 0) |
| { |
| if (errno == EWOULDBLOCK) |
| { |
| if(try_count == times) |
| { |
| LOGD("read timeout"); |
| return -1; |
| } |
| usleep(50000); |
| goto TCP_READ_AGAIN; |
| } |
| else |
| { |
| LOGE("read error.[%d]", errno); |
| return -1; |
| } |
| } |
| |
| LOGV("Read data[%d/%d].", len, buf_len); |
| |
| return len; |
| } |
| |
| #if 0 |
| int sock_readline(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err) |
| { |
| if (sock_info->fd > 0) |
| { |
| char *buf_ptr = (char*)buffer; |
| char read_buf[1]; |
| int read_len = 0; |
| while (TRUE) |
| { |
| if (sock_read_async(net_info, sock_info, read_buf, 1, timeout, err) == 1) |
| { |
| *buf_ptr++ = read_buf[0]; |
| read_len++; |
| |
| if (read_buf[0] == '\n' || read_len >= buf_len) |
| { |
| return read_len; |
| } |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| } |
| return -1; |
| } |
| #else |
| int sock_readline(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err) |
| { |
| if (sock_info->fd > 0) |
| { |
| memset(buffer,0,buf_len); |
| int read_len = 0; |
| char *buf_ptr = (char*)buffer; |
| char *temp_ptr = sock_info->read_buff.buffer; |
| |
| LOGV("TEMP buffer[fd - %d, len-%d]:%s", sock_info->fd, sock_info->read_buff.size, sock_info->read_buff.buffer); |
| copy_angin: |
| while(sock_info->read_buff.size > 0 && *temp_ptr != '\n') { |
| *buf_ptr++ = *temp_ptr++; |
| sock_info->read_buff.size--; |
| read_len++; |
| } |
| |
| LOGV("SIZE : %d,TEMP is \\n : %d", sock_info->read_buff.size, *temp_ptr == '\n'); |
| |
| if(sock_info->read_buff.size == 0) { |
| sock_info->read_buff.size = sock_read(net_info, sock_info, sock_info->read_buff.buffer, |
| sock_info->read_buff.size_max, timeout, err); |
| if(sock_info->read_buff.size <= 0) { |
| if(read_len == 0) { // No data. |
| LOGE("sock_read() fail."); |
| return -1; |
| } else { |
| return read_len; |
| } |
| } |
| |
| temp_ptr = sock_info->read_buff.buffer; |
| goto copy_angin; |
| } else if(*temp_ptr == '\n') { // Read line. |
| *buf_ptr++ = '\n'; |
| sock_info->read_buff.size--; |
| read_len++; |
| |
| if(sock_info->read_buff.size > 0) |
| memcpy(sock_info->read_buff.buffer, temp_ptr + 1, sock_info->read_buff.size); |
| |
| return read_len; |
| } |
| |
| } |
| return -1; |
| } |
| #endif |
| |
| int sock_write(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, const void *buffer, uint32 buf_len, uint32 timeout, int *err) |
| { |
| int len = 0; |
| uint32 try_count = 0; |
| uint32 times = timeout * 100; |
| unsigned int count = 0; |
| while (count < buf_len) |
| { |
| try_count++; |
| if (sock_info->is_ssl) |
| { |
| //printf(" try_count = %d timeout = %d sock_info->is_ssl = 1\n",try_count,timeout); |
| if(try_count >= times) |
| { |
| printf("over time \n"); |
| break; |
| } |
| } |
| else |
| { |
| len = write(sock_info->fd, (const char*)buffer + count, buf_len - count); |
| } |
| if (len < 0) |
| { |
| if (errno == EWOULDBLOCK) |
| { |
| usleep(50000); |
| continue; |
| } |
| else |
| { |
| LOGE("write error.[%d]", errno); |
| if (count <= 0) |
| count = -1; |
| break; |
| } |
| } |
| else if (len == 0) |
| { |
| LOGE("write error(len == 0).[%d]", errno); |
| } |
| else |
| { |
| count += len; |
| } |
| } |
| |
| if (count > 0) |
| { |
| LOGV("Write data[%d/%d] success.", count, buf_len); |
| } |
| else // Open session fail |
| { |
| LOGV("Write data[%d/%d] fail.", count, buf_len); |
| } |
| |
| return count; |
| } |
| |
| int sock_recv(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout) |
| { |
| unsigned int count = 0; |
| int len = 0; |
| int try_count = 0; |
| int times = timeout / 50; // ms |
| memset(buffer, 0x0, buf_len); |
| while (count < buf_len) |
| { |
| try_count++; |
| len = recvfrom(sock_info->fd, (char*) buffer + count, buf_len - count, 0, |
| (struct sockaddr *)&sock_info->addr.addr.serverSockAddr, (socklen_t *)&sock_info->addr.addr_len); |
| if (len <= 0) |
| { |
| if (errno == EWOULDBLOCK || errno == EAGAIN) |
| { |
| if (count > 0) // Read data |
| break; // Read data end. |
| |
| if (try_count >= times) // Timeout |
| { |
| count = -1; |
| break; |
| } |
| else |
| { |
| usleep(50000); |
| continue; |
| } |
| } |
| else if (errno == EINPROGRESS) |
| { |
| if (close(sock_info->fd) == 0) // Success |
| { |
| LOGD("Socket disconnected.Close it."); |
| } |
| if (count <= 0) |
| count = -1; |
| break; |
| } |
| else |
| { |
| LOGE("recv error.[%d]", errno); |
| if (count <= 0) |
| count = -1; |
| break; |
| } |
| } |
| else |
| { |
| count += len; |
| } |
| } |
| |
| LOGV("Read data[%d/%d].", count, buf_len); |
| |
| return count; |
| } |
| |
| int sock_sendto(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, const void *buffer, uint32 buf_len, uint32 timeout) |
| { |
| int len = 0; |
| unsigned int count = 0; |
| int try_count = 0; |
| int times = timeout / 50; // ms |
| while (count < buf_len) |
| { |
| try_count++; |
| len = sendto(sock_info->fd,(char*) buffer + count, buf_len - count, 0, |
| (struct sockaddr *)&sock_info->addr.addr.serverSockAddr, sock_info->addr.addr_len); |
| if (len < 0) |
| { |
| if (errno == EWOULDBLOCK) |
| { |
| if (count > 0) // Send part data |
| break; |
| |
| if (try_count >= times) // Timeout |
| { |
| count = -1; |
| break; |
| } |
| else |
| { |
| usleep(50000); |
| continue; |
| } |
| } |
| else |
| { |
| LOGE("sendto error.[%d]", errno); |
| if (count <= 0) |
| count = -1; |
| break; |
| } |
| } |
| else if (len == 0) |
| { |
| LOGE("write error(len == 0).[%d]", errno); |
| } |
| else |
| { |
| count += len; |
| } |
| } |
| |
| if (count == buf_len) |
| { |
| LOGV("Sendto data[%d/%d] success.", count, buf_len); |
| } |
| else |
| { |
| LOGV("Sendto data[%d/%d] fail.", count, buf_len); |
| } |
| |
| return count; |
| } |
| |
| int sock_close(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, uint32 timeout, int *err) |
| { |
| if(sock_info->fd > 0) { |
| if(close(sock_info->fd) < 0) |
| { |
| LOGE("Close socket fail[%d].", errno); |
| return -1; |
| } |
| sock_info->fd = -1; |
| } |
| |
| if(sock_info->read_buff.buffer) { |
| free(sock_info->read_buff.buffer); |
| sock_info->read_buff.buffer = NULL; |
| } |
| return 0; |
| } |
| |
| int sock_net_close(mbtk_net_info_s *net_info, uint32 timeout, int *err) |
| { |
| return 0; |
| } |
| |