#include "sock_conn.h" /*mvar things*/ //shitty macro #define MVAR_ALLOC_STRC(VNAME,VTYPE,VRET)\ VTYPE *VNAME;\ VNAME=malloc(sizeof(VTYPE));\ if ((VNAME)==NULL){\ VRET\ }\ memset(VNAME,0,sizeof(VTYPE)); #define MVAR_ALLOC_ARR(VNAME,VTYPE,VSZ,VRET)\ VTYPE *VNAME;\ VNAME=malloc(sizeof(VTYPE)*(VSZ));\ if ((VNAME)==NULL){\ VRET\ }\ memset(VNAME,0,sizeof(VTYPE)*(VSZ)); irc_buf* irc_buf_create() { MVAR_ALLOC_STRC(ret,irc_buf,{ return NULL; }); ret->out_size = 0; ret->max_out_size = IRC_BUF_OUT_SIZE; ret->buf_out = malloc(ret->max_out_size); if (ret->buf_out == NULL) { free(ret); PERM(); return NULL; } memset(ret->buf_out, 0, ret->max_out_size); ret->in_size = 0; ret->max_in_size = IRC_BUF_IN_SIZE; ret->buf_in = malloc(ret->max_in_size); if (ret->buf_in == NULL) { free(ret->buf_out); free(ret); return NULL; } memset(ret->buf_in, 0, ret->max_in_size); ret->ready = 0; return ret; } //cpy bytes from input to output int __irc_buf_drain_io(irc_buf *ib) { int cnt=0; int i; int j; //out buffer is allready full if (ib->out_size-1 == ib->max_out_size) { PRINT("Out buffer is full\n"); return -1; } //check if buffer is complete buffer if (ib->ready == 1) //its marked as complete { PRINT("Buffear allready ready\n"); return 0; } //in case if its not marked, -1 becouse its index in array if ((ib->out_size >= 2) &&(ib->buf_out[ib->out_size-1]=='\n') &&(ib->buf_out[ib->out_size-2]=='\r')) { PRINT("Buffer is ready\n"); return 0; } //BUG //here is hope that server will send 512/1024 bytes that will be terminated with "\r\n" //but this could be false hope if someone gona abuse it, buffer will fill up and will //not be able to give back new lines //FIX //just add more logic pal to handle this "special" case //lets from in buffer put as much as possible to out buffer i = ib->in_size-1; j = ib->out_size; //PRINT("in_size=%d out_size=%d\n",ib->in_size, ib->out_size); cnt = 0; while ((jmax_out_size)&&(i>=0)) //buffers ar full or empty { //if (ib->out_size >= 2) if (j >= 3) //be carefull with this line { if (((ib->buf_out[j-3]=='\r')&&(ib->buf_out[j-2]=='\n')))//bufferunderflow { //PRINT("READY\n"); ib->ready = 1; //PNL(); break; } } ib->buf_out[j] = ib->buf_in[i]; i--; j++; cnt++; } //update //PRINT("Copied %d bytes\n", cnt); ib->in_size = i+1; //i can end up as -1 ib->out_size = j; // //PRINT("in_size=%d out_size=%d\n",ib->in_size, ib->out_size); //if out buffer full and its doesnt have proper ending if (ib->out_size >= 2) if ((ib->buf_out[ib->out_size-1]=='\n')&&(ib->buf_out[ib->out_size-2]=='\r')) { //PRINT("READY\n"); ib->ready = 1; return cnt; } //PRINT("%d\n",cnt); return cnt; } //return amount not written bytes int irc_buf_puts(irc_buf *ib, char *in_buf, int sz) { int i,j; int cnt; int ret = -1; int fret = -1; if (ib == NULL) { PERM(); return -1; } if (in_buf == NULL) { PERM(); return -1; } if (sz<0) { PERM(); return -1; } cnt = 0; for ( i=0, j=ib->in_size,cnt=0; (imax_in_size); i++, j++,cnt++) { //PRINT("%d %d\n",i,j); ib->buf_in[j] = in_buf[sz-i-1]; } ib->in_size = j; fret = __irc_buf_drain_io(ib); if (fret == 0) { printf("Cant do it pal\n"); } //printf("%d %d\n",sz,cnt); ret = fret; return ret; } int irc_buf_putc(irc_buf *ib, char c) { printf("Not implemtented\n"); return -1; } //return size of output buffer int irc_buf_sz(irc_buf *ib) { if (ib == NULL) return -1; return ib->out_size; } int irc_buf_ready(irc_buf *ib) { if (ib == NULL) { return -1; } return ib->ready; } //unset ready and return line char *irc_buf_line(irc_buf *ib) { char *ret = NULL; if (ib == NULL) { PERM(); return NULL; } if (ib->ready == 0) { PERM(); return NULL; } ret = alloc_new_str_s(ib->buf_out, ib->out_size); if (ret == NULL) { PERM(); return NULL; } ib->ready = 0; ib->out_size = 0; return ret; } int irc_buf_destroy(irc_buf *ib) { if (ib == NULL) { return -1; } free(ib->buf_in); free(ib->buf_out); free(ib); return 0; } /* connect to hostname:port return fd>0 if connection succesful */ int irc_connect( char *hostname, char *port ) { int fd=0; int fret=-1; struct addrinfo serv, *res; if (hostname == NULL) { PERM(); return -1; } if (port == NULL) { PERM(); return -1; } memset(&serv, 0, sizeof(serv)); serv.ai_family = AF_INET; serv.ai_socktype = SOCK_STREAM; if (0 != getaddrinfo(hostname, port, &serv, &res)) { PERM(); perror("CONNECT: Couldnt get addr info"); return -1; } fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); fret = connect(fd, res->ai_addr, res->ai_addrlen); if (fret!=0) { PERM(); freeaddrinfo(res); return -1; } freeaddrinfo(res); return fd; } int irc_open(char *hostname, char *port, irc_conn *conn) { int fd, fret; struct addrinfo serv, *res=NULL;//_res, *res=&_res; 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); free(conn->hostname); free(conn->port); freeaddrinfo(res); 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"); free(conn->hostname); free(conn->port); freeaddrinfo(res); 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(); free(conn->hostname); free(conn->port); freeaddrinfo(res); return -1; } //set non blocking fcntl(fd, F_SETFL, O_NONBLOCK); conn->conn_fd = fd; conn->err = ERR_SC_NONE; conn->liberr = 0; freeaddrinfo(res); 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; fret = read(conn->conn_fd, buf, sz); save_err = errno; if (fret<0) { if (save_err == EAGAIN) { uint64_t proc_sec; struct timespec cur_clock; //if last time was without error then lets update last error clock if (conn->err == ERR_SC_NONE) { clock_gettime(CLOCK_REALTIME, &conn->last_read); } if (conn->timeout > 0) { //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; char *hostname=NULL; char *port=NULL; int timeout=-1; irc_conn reconn; if (conn == NULL) { PERM(); return -1; } //close connection close(conn->conn_fd); hostname = conn->hostname; port = conn->port; timeout = timeout; fret = irc_open(hostname, port, &reconn); if (-1 == fret) { ENL(); return -1; } if (-1 == irc_read_timeout(&reconn, timeout)) { ENL(); } free(conn->hostname); conn->hostname = NULL; free(conn->port); conn->port = NULL; memcpy(conn, &reconn, sizeof(irc_conn)); return 0; } int irc_close(irc_conn *conn) { if (conn == NULL) { PERM(); return -1; } close(conn->conn_fd); free(conn->hostname); free(conn->port); return 0; }