// // Copyright (c) <2014>, skysent // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // 3. All advertising materials mentioning features or use of this software // must display the following acknowledgement: // This product includes software developed by skysent. // 4. Neither the name of the skysent nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY skysent ''AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL skysent BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void ytcpsocket_set_block(int socket, int on) { int flags; flags = fcntl(socket, F_GETFL, 0); if (on == 0) { fcntl(socket, F_SETFL, flags | O_NONBLOCK); } else { flags &= ~ O_NONBLOCK; fcntl(socket, F_SETFL, flags); } } int ytcpsocket_connect(const char *host, int port, int timeout) { struct sockaddr_in sa; struct hostent *hp; int sockfd = -1; hp = gethostbyname(host); if (hp == NULL) { return -1; } bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length); sa.sin_family = hp->h_addrtype; sa.sin_port = htons(port); sockfd = socket(hp->h_addrtype, SOCK_STREAM, 0); ytcpsocket_set_block(sockfd,0); connect(sockfd, (struct sockaddr *)&sa, sizeof(sa)); fd_set fdwrite; struct timeval tvSelect; FD_ZERO(&fdwrite); FD_SET(sockfd, &fdwrite); tvSelect.tv_sec = timeout; tvSelect.tv_usec = 0; int retval = select(sockfd + 1, NULL, &fdwrite, NULL, &tvSelect); if (retval < 0) { close(sockfd); return -2; } else if(retval == 0) {//timeout close(sockfd); return -3; } else { int error = 0; int errlen = sizeof(error); getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&errlen); if (error != 0) { close(sockfd); return -4;//connect fail } int set = 1; setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); return sockfd; } } int ytcpsocket_close(int socketfd){ return close(socketfd); } int ytcpsocket_pull(int socketfd, char *data, int len, int timeout_sec) { int readlen = 0; int datalen = 0; if (timeout_sec > 0) { fd_set fdset; struct timeval timeout; timeout.tv_usec = 0; timeout.tv_sec = timeout_sec; FD_ZERO(&fdset); FD_SET(socketfd, &fdset); int ret = select(socketfd + 1, &fdset, NULL, NULL, &timeout); if (ret <= 0) { return ret; // select-call failed or timeout occurred (before anything was sent) } } ytcpsocket_set_block(socketfd, (timeout_sec < 0)); // use loop to make sure receive all data do { readlen = (int)read(socketfd, data + datalen, len - datalen); if (readlen > 0) { datalen += readlen; } } while (readlen > 0); return datalen; } int ytcpsocket_bytes_available(int socketfd) { int count; int callResult = ioctl(socketfd, FIONREAD, &count); if (callResult < 0) { return callResult; } return count; } int ytcpsocket_send(int socketfd, const char *data, int len){ int byteswrite = 0; while (len - byteswrite > 0) { int writelen = (int)write(socketfd, data + byteswrite, len - byteswrite); if (writelen < 0) { return -1; } byteswrite += writelen; } return byteswrite; } //return socket fd int ytcpsocket_listen(const char *address, int port) { //create socket int socketfd = socket(AF_INET, SOCK_STREAM, 0); int reuseon = 1; setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &reuseon, sizeof(reuseon)); //bind struct sockaddr_in serv_addr; memset( &serv_addr, '\0', sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr(address); serv_addr.sin_port = htons(port); int r = bind(socketfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); if (r == 0) { if (listen(socketfd, 128) == 0) { return socketfd; } else { return -2;//listen error } } else { return -1;//bind error } } //return client socket fd int ytcpsocket_accept(int onsocketfd, char *remoteip, int *remoteport, int timeouts) { socklen_t clilen; struct sockaddr_in cli_addr; clilen = sizeof(cli_addr); fd_set fdset; FD_ZERO(&fdset); FD_SET(onsocketfd, &fdset); struct timeval *timeptr = NULL; struct timeval timeout; if (timeouts > 0) { timeout.tv_sec = timeouts; timeout.tv_usec = 0; timeptr = &timeout; } int status = select(FD_SETSIZE, &fdset, NULL, NULL, timeptr); if (status != 1) { return -1; } int newsockfd = accept(onsocketfd, (struct sockaddr *) &cli_addr, &clilen); char *clientip=inet_ntoa(cli_addr.sin_addr); memcpy(remoteip, clientip, strlen(clientip)); *remoteport = cli_addr.sin_port; if (newsockfd > 0) { int set = 1; setsockopt(newsockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*) &set, sizeof(int)); return newsockfd; } else { return -1; } } //return socket port int ytcpsocket_port(int socketfd) { struct sockaddr_in sin; socklen_t len = sizeof(sin); if (getsockname(socketfd, (struct sockaddr *)&sin, &len) == -1) { return -1; } else { return ntohs(sin.sin_port); } }