#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," "); if(word1==NULL){ free(buf); return NULL; } TcpResponseType type; char *gameidvalue,*roomidvalue; //Not yet strdup'd! i64 idvalue; char *messagevalue; i64 intvalue; TcpList *listvalue=NULL; char *errorvalue=NULL; //Not yet strdup'd! if(strcmp(word1,"room_join")==0||strcmp(word1,"room_leave")==0||strcmp(word1,"room_message")==0){ if(word1[5]=='j')type=TCP_PUSH_JOIN; else if(word1[5]=='l')type=TCP_PUSH_LEAVE; else type=TCP_PUSH_MESSAGE; char *w1=strsep(&walker," "); char *w2=strsep(&walker," "); char *w3=strsep(&walker," "); if(w1==NULL||w2==NULL||w3==NULL||(type==TCP_PUSH_MESSAGE?walker==NULL:walker!=NULL)){ free(buf); return NULL; } gameidvalue=w1; roomidvalue=w2; char *endp; idvalue=strtoll(w3,&endp,10); if(w3[0]=='\0'||*endp!='\0'||idvalue<0){ free(buf); return NULL; } if(type==TCP_PUSH_MESSAGE){ char *w4=strsep(&walker," "); if(w4==NULL||walker!=NULL){ free(buf); return NULL; } char *endp; i64 msglength=strtoll(w4,&endp,10); if(w4[0]=='\0'||*endp!='\0'||msglength<0){ free(buf); return NULL; } messagevalue=malloc(msglength+1,char); if(tcp_read_data(sock,messagevalue,msglength)==-1){ free(buf); free(messagevalue); return NULL; } messagevalue[msglength]='\0'; } } else { char *word2=strsep(&walker," "); if(word2==NULL||strcmp(word2,tag)!=0){ free(buf); return 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=strdup(errorvalue); break; case TCP_INT: res->ival=intvalue; break; case TCP_LIST: res->lval=listvalue; break; case TCP_PUSH_JOIN: case TCP_PUSH_LEAVE: res->jval.gameid=strdup(gameidvalue); res->jval.roomid=strdup(roomidvalue); res->jval.id=idvalue; break; case TCP_PUSH_MESSAGE: res->mval.gameid=strdup(gameidvalue); res->mval.roomid=strdup(roomidvalue); res->mval.id=idvalue; res->mval.message=messagevalue; break; } free(buf); 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; case TCP_PUSH_JOIN: case TCP_PUSH_LEAVE: free(res->jval.gameid); free(res->jval.roomid); break; case TCP_PUSH_MESSAGE: free(res->mval.gameid); free(res->mval.roomid); free(res->mval.message); 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; }