/* select.c - my [complex] example of using select() in a socket program */ /* Jon Mayo - December 2006 - PUBLIC DOMAIN - NO COPYRIGHT CLAIMED */ /* version 0.002 */ #include #include #include #include #include #include #include #include #include #define MAX_CLIENTS 512 /* data for each client */ static struct client { int fd; int delay; } client[MAX_CLIENTS]; static unsigned nr_client = 0; static int client_print(int fd, const char *str) { size_t len; len=strlen(str); return send(fd, str, len, MSG_DONTWAIT); } static void client_printall(int my_fd, const char *str) { int i; for(i=0;i 0); *cl=client[--nr_client]; } static void client_prompt(int fd) { client_print(fd, "> "); } /* slow and cheesy way of doing things */ static int client_getline(int fd, char *buf, size_t maxlen) { int len; char *end; len=recv(fd, buf, maxlen-1, MSG_PEEK); if(len<0) { perror("recv()"); return -1; } else if(len==0) { return -1; /* no line ready - you should delay */ } buf[len]=0; /* null terminate */ if((end=strchr(buf, '\r'))) { int trim=1; /* found a line */ end++; if(*end=='\n') { end++; trim++; } len=recv(fd, buf, end-buf, 0); if(len<0) { perror("recv()"); return -1; } else if(len==0) { return 0; /* closed */ } len-=trim; buf[len]=0; return len; } return -1; /* no line ready - you should delay */ } static int do_client(struct client *cl) { char buf[1024]; int len; assert(cl!=NULL); len=client_getline(cl->fd, buf, sizeof buf); if(len==0) { /* connection closed */ printf("Remote Connection Closed! fd=%d\n", cl->fd); close(cl->fd); cl->fd=-1; /* mark as deleted */ } if(len<0) { /* error or not enough data in string. we should not look for data for * 1 TICK or until other sockets have had their chance to send data. */ cl->delay=1; } else { printf("readline: '%s'\n", buf); if(len+2 >= sizeof buf) { len-=3; /* truncate to make room for \r\n\0 */ } buf[len++]='\r'; buf[len++]='\n'; buf[len++]=0; client_printall(cl->fd, buf); client_prompt(cl->fd); } return 1; } static int new_client(int server_fd) { int fd; struct sockaddr_in sa; socklen_t slen = sizeof sa; fd=accept(server_fd, (struct sockaddr*)&sa, &slen); if(fd<0) { perror("accept()"); return -1; } if(nr_client>=MAX_CLIENTS) { client_print(fd, "too many clients.\r\n"); close(fd); return -1; } printf("Connection! fd=%d\n", fd); /* initialize a new client entry */ client[nr_client].delay=0; /* used to delay reading */ client[nr_client].fd=fd; nr_client++; client_printall(fd, "*** someone connected ***\r\n"); /* send the client a message */ client_print(fd, "WELCOME!\r\n"); client_prompt(fd); return fd; } /* makes a socket suitable for listening TCP and returns the fd */ static int make_server_socket(int port) { int server_fd; struct sockaddr_in sa; assert(port > 0); memset(&sa, 0, sizeof sa); sa.sin_family=AF_INET; /* IPv4 */ sa.sin_port=htons(port); server_fd=socket(sa.sin_family, SOCK_STREAM, 0); /* TCP */ if(server_fd<0) { perror("socket()"); return 0; } if(bind(server_fd, (struct sockaddr *)&sa, sizeof sa)) { perror("bind()"); close(server_fd); return 0; } listen(server_fd, 0); /* this puts our socket in listen mode */ return server_fd; } static int server(int port) { int biggest_fd; int server_fd; int result; int keep_going=1; /* set this to 0 to exit the loop */ fd_set rfds; server_fd=make_server_socket(port); if(server_fd<0) { return 0; /* failure */ } biggest_fd=server_fd; /* initialize it */ FD_ZERO(&rfds); do { struct timeval tv; int i; /* clean up any dead clients */ for(i=0;ibiggest_fd) biggest_fd=newfd; } /* we have data to process. result is count of items to process */ for(i=0; result && i