#include #include #include #include #include #include #include #include #include "command.h" #include "conn_data.h" #include "db.h" #include "runloop.h" #include "user_data.h" #define PORT (29536) // python: int("msg",36) static int create_server_socket(void){ int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0)die_perror("socket"); int one=1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&one,sizeof one); struct sockaddr_in name; name.sin_family=AF_INET; name.sin_addr.s_addr=htonl(INADDR_ANY); name.sin_port=htons(PORT); if(bind(sock,(struct sockaddr*)&name,sizeof name)<0)die_perror("bind"); if(listen(sock,16)<0)die_perror("listen"); return sock; } struct hash_item{ struct conn_data cd; struct hash_item *next; }; #define CONN_HASH_SIZE (16) static struct hash_item *conn_hash[CONN_HASH_SIZE]; static struct conn_data* find_conn_data(int fd){ struct hash_item *item=conn_hash[fd%CONN_HASH_SIZE]; while(item&&item->cd.fd!=fd)item=item->next; assert(item); return &item->cd; } static void delete_conn_data(int fd){ debug("Deleting conn_data for fd=%d",fd); struct hash_item *item=conn_hash[fd%CONN_HASH_SIZE]; assert(item); if(item->cd.fd==fd){ if(item->cd.userid!=-1)userdata_unregister(item->cd.userid,fd); conn_hash[fd%CONN_HASH_SIZE]=item->next; conn_data_nullify(&item->cd); free(item); return; } struct hash_item *parent=NULL; while(item&&item->cd.fd!=fd){ parent=item; item=item->next; } assert(parent); assert(item); if(item->cd.userid!=-1)userdata_unregister(item->cd.userid,fd); conn_data_nullify(&item->cd); parent->next=item->next; free(item); } static bool client_socket_callback(int fd){ struct conn_data *data=find_conn_data(fd); if(data->bufsz-data->buflen<256){ data->bufsz*=2; data->buffer=realloc(data->buffer,data->bufsz,char); } ssize_t ret; do ret=read(fd,data->buffer+data->buflen,data->bufsz-data->buflen); while(ret<0&&errno==EINTR); if(ret<0)die_perror("read"); if(ret==0){ delete_conn_data(fd); close(fd); return true; } data->buflen+=ret; char *lfp=memchr(data->buffer,'\n',data->buflen); if(lfp==NULL)return false; size_t length=lfp-data->buffer; bool should_close=handle_input_line(data,data->buffer,length); memmove(data->buffer,lfp+1,data->buflen-length-1); data->buflen-=length+1; if(should_close){ delete_conn_data(fd); close(fd); return true; } return false; } static bool server_socket_callback(int fd){ int sock; do sock=accept(fd,NULL,NULL); while(sock<0&&errno==EINTR); if(sock<0)die_perror("accept"); runloop_add_fd(sock,client_socket_callback); struct hash_item *item=malloc(1,struct hash_item); conn_data_init(&item->cd,sock); item->next=conn_hash[sock%CONN_HASH_SIZE]; conn_hash[sock%CONN_HASH_SIZE]=item; debug("Added conn_data for fd=%d",sock); return false; } int main(void){ srandomdev(); db_init(); int sock=create_server_socket(); printf("Listening on port %d\n",PORT); runloop_add_fd(sock,server_socket_callback); runloop_run(); db_close(); }