Add tcp_connect() and tcp_read()
This commit is contained in:
parent
b2f7e04b8d
commit
3c92fe070c
2 changed files with 159 additions and 3 deletions
157
tcp.c
157
tcp.c
|
@ -17,7 +17,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -635,8 +637,147 @@ tcp_set_hostname(tcp_session_t *ses, const char *hostname)
|
||||||
|
|
||||||
#endif
|
#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
|
int
|
||||||
tcp_write_queue(int fd, htsbuf_queue_t *q)
|
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;
|
l = hd->hd_data_len - hd->hd_data_off;
|
||||||
r = write(fd, hd->hd_data + hd->hd_data_off, l);
|
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->hd_data);
|
||||||
free(hd);
|
free(hd);
|
||||||
}
|
}
|
||||||
|
@ -752,8 +890,21 @@ tcp_read_data(int fd, char *buf, const size_t bufsize, htsbuf_queue_t *spill)
|
||||||
return 0;
|
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
5
tcp.h
|
@ -105,11 +105,16 @@ int tcp_send_msg(tcp_session_t *ses, int hiprio, void *data, size_t len);
|
||||||
|
|
||||||
void tcp_server_init(void);
|
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,
|
typedef void (tcp_server_callback_t)(int fd, void *opaque,
|
||||||
struct sockaddr_in *source);
|
struct sockaddr_in *source);
|
||||||
|
|
||||||
void *tcp_server_create(int port, tcp_server_callback_t *start, void *opaque);
|
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,
|
int tcp_read_line(int fd, char *buf, const size_t bufsize,
|
||||||
htsbuf_queue_t *spill);
|
htsbuf_queue_t *spill);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue