diff options
Diffstat (limited to 'tcp.c')
-rw-r--r-- | tcp.c | 157 |
1 files changed, 157 insertions, 0 deletions
@@ -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; +} |