ListenerApp/ListenerGS/SwiftSocket/ytcpsocket.c

225 lines
6.8 KiB
C

//
// 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <dirent.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/ioctl.h>
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);
}
}