summaryrefslogtreecommitdiff
path: root/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'tcp.c')
-rw-r--r--tcp.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/tcp.c b/tcp.c
new file mode 100644
index 0000000..a254b99
--- /dev/null
+++ b/tcp.c
@@ -0,0 +1,157 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include "global.h"
+#include "memory.h"
+#include "tcp.h"
+
+i64 tcp_read_line(int sock,char **buf,i64 *bufsz){
+ if(*bufsz==0||*buf==NULL){
+ *bufsz=512;
+ *buf=malloc(*bufsz,char);
+ }
+ i64 len=0;
+ while(true){
+ if(len==*bufsz-1){
+ *bufsz*=2;
+ *buf=realloc(*buf,*bufsz,char);
+ }
+ i64 ret=recv(sock,*buf+len,1,0);
+ if(ret<=0)return -1;
+ if((*buf)[len]=='\n'){
+ (*buf)[len]='\0';
+ return len;
+ }
+ len++;
+ }
+}
+
+i64 sock_read_data(int sock,char *buf,i64 length){
+ i64 got=0;
+ while(got<length){
+ i64 ret=recv(sock,buf+got,length-got,0);
+ if(ret<=0)return -1;
+ got+=ret;
+ }
+ return 0;
+}
+
+i64 tcp_send_data(int sock,const char *buf,i64 length){
+ i64 sent=0;
+ while(sent<length){
+ i64 ret=send(sock,buf+sent,length-sent,0);
+ if(ret==-1){
+ if(errno==EINTR)continue;
+ return -1;
+ }
+ sent+=ret;
+ }
+ return 0;
+}
+
+i64 tcp_send_str(int sock,const char *str){
+ return tcp_send_data(sock,str,strlen(str));
+}
+
+i64 tcp_send_line(int sock,const char *str){
+ if(tcp_send_str(sock,str)==-1)return -1;
+ return tcp_send_str(sock,"\n");
+}
+
+__attribute__((format (printf,2,3)))
+i64 sock_send_line_f(int sock,const char *format,...){
+ va_list ap;
+ va_start(ap,format);
+ char *buf;
+ vasprintf(&buf,format,ap);
+ va_end(ap);
+ if(buf==NULL)throw("vasprintf: allocation failure");
+ i64 ret=tcp_send_line(sock,buf);
+ free(buf);
+ return ret;
+}
+
+
+i64 tcp_read_ok(int sock,const char *tag){
+ char *buf=NULL;
+ i64 bufsz=0;
+ i64 ret=tcp_read_line(sock,&buf,&bufsz);
+ if(ret==-1){
+ if(buf!=NULL)free(buf);
+ return -1;
+ }
+
+ char *walker=buf;
+ char *ok=strsep(&walker," ");
+ char *realtag=strsep(&walker," ");
+ bool success=walker==NULL&&strcmp(ok,"ok")==0&&strcmp(realtag,tag)==0;
+ free(buf);
+ return success?0:-1;
+}
+
+TcpList* tcp_read_list(int sock,const char *tag){
+ char *buf=NULL;
+ i64 bufsz=0;
+ i64 ret=tcp_read_line(sock,&buf,&bufsz);
+ if(ret==-1){
+ if(buf!=NULL)free(buf);
+ return NULL;
+ }
+
+ char *walker=buf;
+ char *word1=strsep(&walker," ");
+ char *word2=strsep(&walker," ");
+ char *word3=strsep(&walker," ");
+ char *argstart=walker;
+ i64 nitems=0;
+ while((strsep(&walker," "))!=NULL)nitems++;
+ if(word1==NULL||word2==NULL||word3==NULL||strcmp(word1,"list")!=0||strcmp(word2,tag)!=0){
+ free(buf);
+ return NULL;
+ }
+ char *endp;
+ i64 word3i=strtol(word3,&endp,10);
+ if(word3[0]=='\0'||*endp!='\0'||word3i!=nitems){
+ free(buf);
+ return NULL;
+ }
+
+ TcpList *list=malloc(1,TcpList);
+ list->nitems=nitems;
+ list->items=malloc(nitems,char*);
+ walker=argstart;
+ for(i64 i=0;i<nitems;i++){
+ list->items[i]=strdup(strsep(&walker," "));
+ }
+
+ return list;
+}
+
+
+static const char* itoa(int n){
+ static char buf[64];
+ sprintf(buf,"%d",n);
+ return buf;
+}
+
+
+int tcp_connect(const char *hostname,int port){
+ struct addrinfo hints,*res;
+ memset(&hints,0,sizeof(hints));
+ hints.ai_family=AF_UNSPEC;
+ hints.ai_socktype=SOCK_STREAM;
+ int ret=getaddrinfo(hostname,itoa(port),&hints,&res);
+ if(ret!=0){
+ return -1;
+ }
+
+ int sock=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
+ if(sock==-1)return -1;
+ if(connect(sock,res->ai_addr,res->ai_addrlen)==-1)return -1;
+ return sock;
+}