You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
7.3 KiB
274 lines
7.3 KiB
#pragma once |
|
#include <arpa/inet.h> |
|
#include <sys/socket.h> |
|
#include <unistd.h> |
|
#include <stdio.h> |
|
#include <signal.h> |
|
#include <sys/select.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <stdlib.h> |
|
#include <sys/types.h> |
|
#include <netdb.h> |
|
#include <string.h> |
|
#include <sys/time.h> |
|
#define ERR_INET_ADDR "0.9.9.0" |
|
#define TCPC_READ_BUF 1048576 /* en megabajt */ |
|
#define TCPC_RESOLVE_RETRIES 12 |
|
union ip_conv { |
|
unsigned char c[4]; |
|
struct in_addr in; |
|
}; |
|
struct in_addr hostname_to_ip (const char * hostname) { |
|
struct hostent *he; /* STATIC! */ |
|
union ip_conv ipconverter; |
|
struct in_addr *error_addr = malloc(sizeof(struct in_addr)); |
|
/* int ret = */ inet_aton(ERR_INET_ADDR, error_addr); /* TODO: chek for err */ |
|
if ( (he = gethostbyname(hostname)) == NULL ) { |
|
herror("gethostbyname"); |
|
return *error_addr; |
|
} else { |
|
memcpy(ipconverter.c, he->h_addr, 4); // fuck yes now it works |
|
// fprintf(stderr, "debug: %s\n", inet_ntoa(ipconverter.in)); |
|
return ipconverter.in; |
|
} |
|
} |
|
int spawn_conn (const char * address, const int port) { |
|
int ret; |
|
int conn_fd; |
|
struct sockaddr_in server_addr = { 0 }; |
|
unsigned short int r /* etries */= TCPC_RESOLVE_RETRIES; |
|
server_addr.sin_family = AF_INET; |
|
server_addr.sin_port = htons(port); |
|
ret = inet_pton(AF_INET, address, &server_addr.sin_addr); |
|
if (ret != 1) { |
|
if (ret == -1) |
|
perror("inet_pton"); |
|
fprintf(stderr, "%s is not an IPv4, trying to resolve ...\n", address); |
|
struct in_addr ret; /* zakaj sem tudi to poimenoval ret!? sicer dela. */ |
|
struct in_addr error_addr; |
|
retry_resolve: |
|
ret = hostname_to_ip(address); |
|
inet_aton(ERR_INET_ADDR, &error_addr); |
|
if (memcmp(&ret, &error_addr, 4) == 0) { |
|
fprintf(stderr, "failed to resolve-%s.\n", r ? "retrying" : "failing"); |
|
if (r--) |
|
goto retry_resolve; |
|
return -1; |
|
} |
|
server_addr.sin_addr = ret; |
|
fprintf(stderr, "resolved to %s.\n", inet_ntoa(server_addr.sin_addr)); |
|
} |
|
conn_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); |
|
if(conn_fd == -1) { |
|
perror("socket"); |
|
return -1; |
|
} |
|
ret = connect(conn_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); |
|
if (ret == 1) { |
|
perror("connect"); |
|
return -1; |
|
} |
|
return conn_fd; |
|
} |
|
|
|
int kill_conn (int conn_fd) { |
|
int ret = shutdown(conn_fd, SHUT_RDWR); // preprečimo tako read kot write.:wq |
|
if (ret == -1) { |
|
perror("shutdown"); |
|
return -1; |
|
} |
|
ret = close(conn_fd); |
|
if (ret == -1) { |
|
perror("close"); |
|
return -1; |
|
} |
|
return 0; |
|
} |
|
|
|
int read_until(int conn_fd, FILE * out, unsigned int timeout, const char * ma, |
|
unsigned long long int max_bytes) { |
|
int ret = 0; |
|
unsigned int match = 0; |
|
struct timeval start, stop; |
|
gettimeofday(&start, NULL); |
|
char c[TCPC_READ_BUF+1]; |
|
while (1) { |
|
ret = read(conn_fd, c, ma ? 1 : TCPC_READ_BUF); |
|
if (ret == -1) { |
|
if (errno == EWOULDBLOCK) { |
|
} else { |
|
fprintf(stderr, "%s@" __FILE__ ":%d read(): %s%d\n", __func__, __LINE__, strerror(errno), ret); |
|
return 1; |
|
} |
|
} else if (ret == 0) { /* strežnik ni poslal ničesar */ |
|
fprintf(stderr, "%s@" __FILE__ ":%d read(): server closed connection\n", __func__, __LINE__); |
|
return 0; |
|
} else { |
|
fwrite(c, ret, 1, out); |
|
max_bytes--; |
|
if (max_bytes <= 0) { |
|
return 0; |
|
} |
|
if (ma != NULL) { |
|
if (ma[match] == c[0]) { |
|
match++; |
|
if (match == strlen(ma)) { |
|
return 0; |
|
} |
|
} else { |
|
match = 0; |
|
} |
|
} |
|
} |
|
gettimeofday(&stop, NULL); |
|
if (stop.tv_sec - start.tv_sec > timeout) { |
|
fprintf(stderr, "%s@" __FILE__ ":%d E_TIMEOUT %ld-%ld>%u\n", __func__, |
|
__LINE__, stop.tv_sec, start.tv_sec, timeout); |
|
return 2; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
int sync_write(int conn_fd, const char * req, int len, unsigned int timeout) { |
|
int ret = write(conn_fd, req, len); |
|
struct timeval start, stop; |
|
gettimeofday(&start, NULL); |
|
if (ret == -1) { |
|
if (errno == EBADF) { |
|
fprintf(stderr, "tcp.c: sync_write: write EBADF: %s\n", strerror(errno)); |
|
return -1; |
|
} |
|
while (errno == EWOULDBLOCK) { |
|
ret = write(conn_fd, req, len); |
|
if(ret != -1) { |
|
return 0; |
|
} |
|
gettimeofday(&stop, NULL); |
|
if (stop.tv_sec - start.tv_sec > timeout) { |
|
fprintf(stderr, "tcp.c: sync_write: E_TIMEOUT %ld-%ld>%u\n", |
|
start.tv_sec, stop.tv_sec, timeout); |
|
return -2; |
|
} |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
#if __INCLUDE_LEVEL__ == 0 |
|
static volatile int sigint = 0; |
|
void intHandler(int sig) { |
|
signal(sig, SIG_IGN); |
|
if (sig == SIGINT) |
|
sigint++; |
|
if (sigint >= 3) // some people smash CtrlC multiple times to force quit! |
|
exit(130); |
|
signal(sig, intHandler); |
|
} |
|
int main (int argc, char ** argv) { |
|
if (argc != 1+2) { |
|
fprintf(stderr, "usage: %s ip.v4.ad.dr port\n", argv[0]); |
|
return 1; |
|
} |
|
signal(SIGINT, intHandler); |
|
#define ADDRESS_ARG argv[1] |
|
#define PORT_ARG argv[2] |
|
int conn_fd = spawn_conn(ADDRESS_ARG, atoi(PORT_ARG)); |
|
if (conn_fd < 0) { |
|
fprintf(stderr, "error connecting!\n"); |
|
return 2; |
|
} else { |
|
fprintf(stderr, "suc. conn with fd %d\n\n", conn_fd); |
|
} |
|
int buf = 0; |
|
#define READ_MAX_SIZE 1024 |
|
char read_buf[READ_MAX_SIZE]; |
|
int i = 0; |
|
char input; |
|
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK); |
|
while (1) { |
|
if (sigint > 0) { |
|
// fprintf(stderr, "\n" USERSTRING_EXIT_CONFIRM " (y/N)\n"); |
|
// char gotchar = getchar(); |
|
// if (gotchar == 'y' || gotchar == 'Y' || gotchar == 'd' || |
|
// gotchar == 'D' || gotchar == 'j' || gotchar == 'J') { |
|
// kill_conn(conn_fd); |
|
// return 0; |
|
// } |
|
if (kill_conn(conn_fd) == 0) { |
|
fprintf(stderr, "\nconnection killed successfully, exiting ...\n"); |
|
} else { |
|
fprintf(stderr, "\nconnection killing FAILED, exiting ...\n"); |
|
} |
|
return 0; |
|
} |
|
buf = read(conn_fd, read_buf, READ_MAX_SIZE); |
|
if (buf == -1 && errno != EWOULDBLOCK) { |
|
fprintf(stderr, "\nerror reading from socket.\n"); |
|
if (kill_conn(conn_fd) != 0) { |
|
fprintf(stderr, "\nerror killing socket\n"); |
|
return 3; |
|
} |
|
return 4; |
|
} |
|
if (buf == 0) { |
|
fprintf(stderr, "\nserver closed socket\n"); |
|
if (kill_conn(conn_fd) != 0) { |
|
fprintf(stderr, "\nerror killing socket\n"); |
|
return 5; |
|
} |
|
return 6; |
|
} |
|
if (errno == EWOULDBLOCK && buf == -1) { |
|
// no data is on socket; sockets are non blocking. |
|
} else { |
|
buf = write(STDOUT_FILENO, read_buf, buf); |
|
if(buf == -1) { |
|
fprintf(stderr, "\nerror writing to stdout\n"); |
|
return 7; |
|
} |
|
} |
|
buf = read(STDIN_FILENO, read_buf, READ_MAX_SIZE); |
|
if (buf == -1 && errno != EWOULDBLOCK) { |
|
fprintf(stderr, "\nerror reading from stdin\n"); |
|
return 8; |
|
} |
|
if (buf == 0) { |
|
// fprintf(stderr, "\neof on stdin\n"); // that's okay |
|
// return 9; |
|
} |
|
if (errno == EWOULDBLOCK && buf == -1) { |
|
// no data in stdin |
|
} else { |
|
i = write(conn_fd, read_buf, buf); |
|
if (i == -1) { |
|
if(errno != EWOULDBLOCK) { |
|
fprintf(stderr, "\nerror writing to socket\n"); |
|
if(kill_conn(conn_fd) != 0) { |
|
fprintf(stderr, "\nerror killing connection\n"); |
|
return 10; |
|
} |
|
return 12; |
|
} else { |
|
while (i == -1) { |
|
if (errno == EWOULDBLOCK) { |
|
fprintf(stderr, "\nwrite to socket blocked, trying again\n"); |
|
i = write (conn_fd, read_buf, buf); |
|
} else { |
|
fprintf(stderr, "\nerror writing to socket\n"); |
|
if (kill_conn(conn_fd) != 0) { |
|
fprintf(stderr, "\nerror killing connection\n"); |
|
return 13; |
|
} |
|
return 14; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
buf = 0; |
|
} |
|
} |
|
#endif
|
|
|