summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sock_conn.c247
-rw-r--r--sock_conn.h41
2 files changed, 287 insertions, 1 deletions
diff --git a/sock_conn.c b/sock_conn.c
index bc7dfff..57a3acd 100644
--- a/sock_conn.c
+++ b/sock_conn.c
@@ -281,7 +281,7 @@ int irc_connect( char *hostname, char *port )
if (0 != getaddrinfo(hostname, port, &serv, &res))
{
PERM();
- perror("Couldnt get addr info");
+ perror("CONNECT: Couldnt get addr info");
return -1;
}
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
@@ -300,3 +300,248 @@ int irc_connect( char *hostname, char *port )
+int irc_open(char *hostname, char *port, irc_conn *conn)
+{
+ int fd, fret;
+ struct addrinfo serv, *res;
+
+ struct timespec tv;
+ tv.tv_sec = 10;
+ tv.tv_nsec = 0;
+
+ if (conn == NULL)
+ {
+ PERM();
+ return -1;
+ }
+
+ if (hostname == NULL)
+ {
+ PERM();
+ conn->err = ERR_SC_PARAM;
+ return -1;
+ }
+
+ if (port == NULL)
+ {
+ PERM();
+ conn->err = ERR_SC_PARAM;
+ return -1;
+ }
+
+ memset(conn, 0, sizeof(irc_conn));
+ conn->hostname = alloc_new_str(hostname);
+ conn->port = alloc_new_str(port);
+ conn->timeout = 0;
+
+ memset(&serv, 0, sizeof(struct addrinfo));
+ serv.ai_family = AF_INET;
+ serv.ai_socktype = SOCK_STREAM;
+
+ if (0 != getaddrinfo(conn->hostname, conn->port, &serv, &res))
+ {
+ perror("OPEN: Couldnt get addr info");
+ PNL();
+ conn->liberr = errno;
+ conn->err = ERR_SC_CONN;
+ ERROR("%s:%s\n",conn->hostname, conn->port);
+ return -1;
+ }
+
+ fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (fd < 0)
+ {
+ conn->liberr = errno;
+ conn->err = ERR_SC_CONN;
+ perror("OPEN: Couldnt get socket");
+ return -1;
+ }
+
+ fret = connect(fd, res->ai_addr, res->ai_addrlen);
+ if (fret!=0)
+ {
+ conn->err = ERR_SC_CONN;
+ conn->liberr = errno;
+ perror("OPEN: Cant connect");
+ PERM();
+ return -1;
+ }
+
+ //set non blocking
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ conn->conn_fd = fd;
+
+ conn->err = ERR_SC_NONE;
+ conn->liberr = 0;
+
+ return 0;
+}
+
+int irc_read_timeout(irc_conn *conn, int timeout)
+{
+ if (conn == NULL)
+ {
+ PERM();
+ return -1;
+ }
+
+ if (timeout<=0)
+ {
+ conn->timeout = 0;
+ return 0;
+ }
+
+ //woop woop i dont belive you whant 2 hours
+ if (timeout>(60*60*2))
+ {
+ PERM();
+ return -1;
+ }
+
+ /*
+ CHECK PREDIFINED MACROSES IF SUCH FUNCTIONALITY EXCISTS OR NOT
+ */
+ #if _POSIX_C_SOURCE < 199309L
+ ERROR("Dont have clock_gettime functionality\n");
+ #endif
+
+ conn->timeout = timeout;
+ if (-1 == clock_gettime(CLOCK_REALTIME, &conn->last_read))
+ {
+ conn->err = ERR_SC_LIBC;
+ conn->liberr = errno;
+ return -1;
+ }
+
+ conn->err = ERR_SC_NONE;
+ conn->liberr = 0;
+
+
+ return 0;
+}
+
+int irc_read(irc_conn *conn, char *buf, size_t sz)
+{
+ int fret;
+ int save_err;
+
+ //PNL();
+ fret = read(conn->conn_fd, buf, sz);
+ save_err = errno;
+ //PNL();
+ if (fret<0)
+ {
+ //PNL();
+ if (save_err == EAGAIN)
+ {
+ //PNL();
+ uint64_t proc_sec;
+ struct timespec cur_clock;
+
+ //PRINT("%d\n", conn->err);
+ //if last time was without error then lets update last error clock
+ if (conn->err == ERR_SC_NONE)
+ {
+ //PNL();
+ clock_gettime(CLOCK_REALTIME, &conn->last_read);
+ }
+
+ if (conn->timeout > 0)
+ {
+ PNL();
+ //first read of clock is in irc_read_timeout_function
+ if (-1 == clock_gettime(CLOCK_REALTIME, &cur_clock))
+ {
+ conn->err = ERR_SC_LIBC;
+ conn->liberr = errno;
+ ENL();
+ return -1;
+ } else
+ {
+ //who cares about precision
+ //fix if needed more precision
+ proc_sec = cur_clock.tv_sec - conn->last_read.tv_sec;
+ if (proc_sec > conn->timeout)
+ {
+ conn->err = ERR_SC_TIMEOUT;
+ conn->liberr = errno;
+ return -1;
+ }
+ }
+ }
+ conn->err = ERR_SC_AGAIN;
+ conn->liberr = 0;
+ return -1;
+ } else
+ {
+ conn->err = ERR_SC_ANY;
+ conn->liberr = errno;
+ perror("READ: Cant read"); //dont loose errno value
+ return -1;
+ }
+ }
+
+ conn->err = ERR_SC_NONE;
+ conn->liberr = 0;
+
+ //return number of written bytes
+ return fret;
+}
+
+int irc_reconnect(irc_conn *conn)
+{
+ int fret;
+ int fd;
+ char *hostname=NULL;
+ char *port=NULL;
+ int timeout=-1;
+
+ irc_conn reconn;
+
+ if (conn == NULL)
+ {
+ PERM();
+ return -1;
+ }
+
+ //close connection
+ close(conn->conn_fd);
+ fd = conn->conn_fd; //do we need that to restore connection?
+
+ hostname = conn->hostname;
+ port = conn->port;
+ timeout = timeout;
+
+ fret = irc_open(hostname, port, &reconn);
+ if (fret==-1)
+ {
+ PERM();
+ return -1;
+ }
+
+ if (-1 == irc_read_timeout(&reconn, timeout))
+ {
+ PERM();
+ }
+
+ //BUG lets think about this case deeper
+ //free(hostname);
+ //free(port);
+
+ return 0;
+}
+
+int irc_close(irc_conn *conn)
+{
+ if (conn == NULL)
+ {
+ PERM();
+ return -1;
+ }
+
+ close(conn->conn_fd);
+ free(conn->hostname);
+ free(conn->port);
+}
+
diff --git a/sock_conn.h b/sock_conn.h
index 55ef8e0..8cf64be 100644
--- a/sock_conn.h
+++ b/sock_conn.h
@@ -3,9 +3,15 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
#include "util.h"
@@ -38,7 +44,42 @@ int irc_buf_ready(irc_buf *ib);
char *irc_buf_line(irc_buf *ib);
int irc_buf_destroy(irc_buf *ib);
+//connecto to irc
+typedef struct irc_conn
+{
+ int conn_fd; //save connection fd
+ char *hostname;
+ char *port;
+ struct timespec last_read; //when last read where happening
+ int timeout;
+ int err; //local error type
+ int liberr; //save error from libc
+} irc_conn;
+
int irc_connect(char *hostname, char *port);
+//list of errors that will give more precise error description, if there is -1 returned one of this errors happened
+#define ERR_SC_NONE 0 //no errors
+#define ERR_SC_LIBC 1 //error from libc, dont have our own error
+#define ERR_SC_PARAM 2 //something wrong with given params
+#define ERR_SC_TIMEOUT 3 //timeout
+#define ERR_SC_ALLOC 4 //memory allocation error
+#define ERR_SC_CONN 5 //somethign with network connection
+#define ERR_SC_RXTX 6 //read/write issue
+#define ERR_SC_AGAIN 7 //async stuff try read later
+#define ERR_SC_ANY 8 //any other error
+
+//irc_conn preallocated, artifacts can stay if something whent wrong
+int irc_open(char *hostname, char *port, irc_conn *conn);
+//if havent readed for more then [timeout] seconds then assume no connection
+int irc_read_timeout(irc_conn *conn, int timeout);
+//wrapped up usual read, read non blocking, count how long there was no data,
+//and asks to reconnect, use err/liberr to diagnose error
+int irc_read(irc_conn *conn, char *buf, size_t sz);
+//no extra errors
+int irc_reconnect(irc_conn *conn);
+//clean dont free
+int irc_close(irc_conn *conn);
+
#endif