#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #define ERR_INET_ADDR "0.9.9.0" #define TCPC_READ_BUF 1024 /* en kilobajt */ #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