#define _GNU_SOURCE #include #include #include #include #include #include #include #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 tcp_read_data(int sock,char *buf,i64 length){ i64 got=0; while(gotnitems=nitems; list->items=malloc(nitems,char*); walker=argstart; for(i64 i=0;iitems[i]=strdup(strsep(&walker," ")); } return list; } 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; } TcpList *list=interpret_list(buf,tag); free(buf); return list; } void tcp_list_destroy(TcpList *list){ free(list->items); free(list); } TcpResponse* tcp_read_response(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," "); if(word1==NULL||word2==NULL||strcmp(word2,tag)!=0){ free(buf); return NULL; } TcpResponseType type; i64 intvalue; TcpList *listvalue=NULL; char *errorvalue=NULL; if(strcmp(word1,"ok")==0&&walker==NULL){ type=TCP_OK; } else if(strcmp(word1,"error")==0){ type=TCP_ERROR; if(walker==NULL){ free(buf); return NULL; } errorvalue=walker; } else if(strcmp(word1,"int")==0){ type=TCP_INT; char *token=strsep(&walker," "); if(walker!=NULL||token==NULL){ free(buf); return NULL; } char *endp; intvalue=strtoll(token,&endp,10); if(token[0]=='\0'||*endp!='\0'){ free(buf); return NULL; } } else if(strcmp(word1,"list")==0){ type=TCP_LIST; listvalue=interpret_list(buf,tag); if(listvalue==NULL){ free(buf); return NULL; } } else { free(buf); return NULL; } TcpResponse *res=malloc(1,TcpResponse); res->type=type; switch(type){ case TCP_OK: break; case TCP_ERROR: res->eval=errorvalue; break; case TCP_INT: res->ival=intvalue; break; case TCP_LIST: res->lval=listvalue; break; } return res; } void tcp_response_destroy(TcpResponse *res){ switch(res->type){ case TCP_OK: break; case TCP_ERROR: free(res->eval); break; case TCP_INT: break; case TCP_LIST: tcp_list_destroy(res->lval); break; } free(res); } 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; }