diff options
Diffstat (limited to 'tcp.c')
-rw-r--r-- | tcp.c | 266 |
1 files changed, 266 insertions, 0 deletions
@@ -0,0 +1,266 @@ +#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 <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <sys/time.h> +#define ERR_INET_ADDR "0.9.9.0" +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 }; + 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 = hostname_to_ip(address); + struct in_addr error_addr; + inet_aton(ERR_INET_ADDR, &error_addr); + if (memcmp(&ret, &error_addr, 4) == 0) { + fprintf(stderr, "failed to resolve.\n"); + 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[2] = {'\0', '\0'}; + while (1) { + ret = read(conn_fd, c, 1); + 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 { + fputc(c[0], out); + max_bytes--; + if (max_bytes <= 0) { + return 0; + } + 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 |