141 lines
2.9 KiB
C
141 lines
2.9 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <netinet/ip.h>
|
|
#include <arpa/inet.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#include "logging.h"
|
|
|
|
int parse_saddr(const char *addr, struct sockaddr_in *sa)
|
|
{
|
|
char *addr_cpy = strdup(addr);
|
|
if (addr_cpy == NULL) {
|
|
log_print(LOG_WARN, "parse_saddr(): out of memory");
|
|
return -1;
|
|
}
|
|
|
|
char *tmp;
|
|
char *ip = strtok_r(addr_cpy, ":", &tmp);
|
|
if (ip == NULL) {
|
|
free(addr_cpy);
|
|
return -1;
|
|
}
|
|
|
|
char *port = strtok_r(NULL, ":", &tmp);
|
|
if (port == NULL) {
|
|
free(addr_cpy);
|
|
return -1;
|
|
}
|
|
|
|
sa->sin_family = AF_INET;
|
|
sa->sin_port = htons(atoi(port));
|
|
int ret = inet_aton(ip, &sa->sin_addr);
|
|
|
|
free(addr_cpy);
|
|
return (ret != 0) ? 0 : -1;
|
|
}
|
|
|
|
int get_sockaddr(struct sockaddr_in *sa, char *buf, int size)
|
|
{
|
|
return snprintf(buf, size, "%s:%d", inet_ntoa(sa->sin_addr), ntohs(sa->sin_port));
|
|
}
|
|
|
|
char * get_sockaddr_buf(struct sockaddr_in *sa)
|
|
{
|
|
static char buf[24];
|
|
get_sockaddr(sa, buf, sizeof(buf));
|
|
return buf;
|
|
}
|
|
|
|
int tcp_listen_socket(struct sockaddr_in *sa)
|
|
{
|
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sock < 0 ) {
|
|
log_print(LOG_ERROR, "tcp_listen_socket(): socket()");
|
|
return -1;
|
|
}
|
|
|
|
int i = 1;
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i))) {
|
|
log_print(LOG_ERROR, "tcp_listen_socket(): setsockopt(SO_REUSEADDR)");
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
if (bind(sock, (struct sockaddr *)sa, sizeof(*sa))) {
|
|
log_print(LOG_ERROR, "tcp_listen_socket(): bind(%s)", get_sockaddr_buf(sa));
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
if (listen(sock, 8)) {
|
|
log_print(LOG_ERROR, "tcp_listen_socket(): listen()");
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
return sock;
|
|
}
|
|
|
|
int tcp_connect_socket(struct sockaddr_in *sa)
|
|
{
|
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sock < 0 ) {
|
|
log_print(LOG_ERROR, "tcp_connect_socket(): socket()");
|
|
return -1;
|
|
}
|
|
|
|
int flags = fcntl(sock, F_GETFL, 0);
|
|
if (flags < 0) {
|
|
log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_GETFL)");
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
/* non-blocking */
|
|
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK)) {
|
|
log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_SETFL)");
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
int ret = connect(sock, (struct sockaddr *)sa, sizeof(*sa));
|
|
if (ret && errno != EINPROGRESS) {
|
|
log_print(LOG_ERROR, "tcp_connect_socket(): bind(%s)", get_sockaddr_buf(sa));
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
/* reset EINPROGRESS */
|
|
errno = 0;
|
|
|
|
/* blocking */
|
|
if (fcntl(sock, F_SETFL, flags)) {
|
|
log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_SETFL)");
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
return sock;
|
|
}
|
|
|
|
int tcp_connect_error(int fd)
|
|
{
|
|
int err;
|
|
unsigned int err_size = sizeof(err);
|
|
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &err_size)) {
|
|
log_print(LOG_ERROR, "tcp_connect_error(): getsockopt(SO_ERROR)");
|
|
return -1;
|
|
}
|
|
|
|
if (err) {
|
|
errno = err;
|
|
log_print(LOG_ERROR, "tcp_connect_error()");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|