Add tcp_connect() and tcp_read()

This commit is contained in:
Andreas Öman 2008-09-01 18:32:41 +00:00
parent b2f7e04b8d
commit 3c92fe070c
2 changed files with 159 additions and 3 deletions

157
tcp.c
View file

@ -17,7 +17,9 @@
*/
#include <pthread.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <poll.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
@ -635,8 +637,147 @@ tcp_set_hostname(tcp_session_t *ses, const char *hostname)
#endif
/**
*
*/
int
tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize,
int timeout)
{
const char *errtxt;
struct hostent hostbuf, *hp;
char *tmphstbuf;
size_t hstbuflen;
int herr, fd, r, res, err;
struct sockaddr_in6 in6;
struct sockaddr_in in;
socklen_t errlen = sizeof(int);
hstbuflen = 1024;
tmphstbuf = malloc(hstbuflen);
while((res = gethostbyname_r(hostname, &hostbuf, tmphstbuf, hstbuflen,
&hp, &herr)) == ERANGE) {
hstbuflen *= 2;
tmphstbuf = realloc(tmphstbuf, hstbuflen);
}
if(res != 0) {
snprintf(errbuf, errbufsize, "Resolver internal error");
free(tmphstbuf);
return -1;
} else if(herr != 0) {
switch(herr) {
case HOST_NOT_FOUND:
errtxt = "The specified host is unknown";
break;
case NO_ADDRESS:
errtxt = "The requested name is valid but does not have an IP address";
break;
case NO_RECOVERY:
errtxt = "A non-recoverable name server error occurred";
break;
case TRY_AGAIN:
errtxt = "A temporary error occurred on an authoritative name server";
break;
default:
errtxt = "Unknown error";
break;
}
snprintf(errbuf, errbufsize, "%s", errtxt);
free(tmphstbuf);
return -1;
} else if(hp == NULL) {
snprintf(errbuf, errbufsize, "Resolver internal error");
free(tmphstbuf);
return -1;
}
fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
if(fd == -1) {
snprintf(errbuf, errbufsize, "Unable to create socket: %s",
strerror(errno));
free(tmphstbuf);
return -1;
}
/**
* Switch to nonblocking
*/
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
switch(hp->h_addrtype) {
case AF_INET:
memset(&in, 0, sizeof(in));
in.sin_family = AF_INET;
in.sin_port = htons(port);
memcpy(&in.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in));
break;
case AF_INET6:
memset(&in6, 0, sizeof(in6));
in6.sin6_family = AF_INET6;
in6.sin6_port = htons(port);
memcpy(&in6.sin6_addr, hp->h_addr_list[0], sizeof(struct in6_addr));
r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in6));
break;
default:
snprintf(errbuf, errbufsize, "Invalid protocol family");
free(tmphstbuf);
return -1;
}
free(tmphstbuf);
if(r == -1) {
if(errno == EINPROGRESS) {
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLOUT;
pfd.revents = 0;
r = poll(&pfd, 1, timeout * 1000);
if(r == 0) {
/* Timeout */
snprintf(errbuf, errbufsize, "Connection attempt timed out");
close(fd);
return -1;
}
if(r == -1) {
snprintf(errbuf, errbufsize, "poll() error: %s", strerror(errno));
close(fd);
return -1;
}
getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen);
} else {
err = errno;
}
} else {
err = 0;
}
if(err != 0) {
snprintf(errbuf, errbufsize, "%s", strerror(err));
close(fd);
return -1;
}
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
return fd;
}
/**
*
*/
int
tcp_write_queue(int fd, htsbuf_queue_t *q)
{
@ -648,9 +789,6 @@ tcp_write_queue(int fd, htsbuf_queue_t *q)
l = hd->hd_data_len - hd->hd_data_off;
r = write(fd, hd->hd_data + hd->hd_data_off, l);
if(l != r) {
fprintf(stderr, "write error\n");
}
free(hd->hd_data);
free(hd);
}
@ -752,8 +890,21 @@ tcp_read_data(int fd, char *buf, const size_t bufsize, htsbuf_queue_t *spill)
return 0;
}
/**
*
*/
int
tcp_read(int fd, void *buf, size_t len)
{
int x = recv(fd, buf, len, MSG_WAITALL);
if(x == -1)
return errno;
if(x != len)
return ECONNRESET;
return 0;
}
/**
*

5
tcp.h
View file

@ -105,11 +105,16 @@ int tcp_send_msg(tcp_session_t *ses, int hiprio, void *data, size_t len);
void tcp_server_init(void);
int tcp_connect(const char *hostname, int port, char *errbuf,
size_t errbufsize, int timeout);
typedef void (tcp_server_callback_t)(int fd, void *opaque,
struct sockaddr_in *source);
void *tcp_server_create(int port, tcp_server_callback_t *start, void *opaque);
int tcp_read(int fd, void *buf, size_t len);
int tcp_read_line(int fd, char *buf, const size_t bufsize,
htsbuf_queue_t *spill);