summaryrefslogtreecommitdiffstats
path: root/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'tcp.c')
-rw-r--r--tcp.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/tcp.c b/tcp.c
new file mode 100644
index 0000000..d30e7b5
--- /dev/null
+++ b/tcp.c
@@ -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