/* minazuki1-linux.c - Don Yang (uguu.org) 07/03/02 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int writer_active; static int sock, s2; static struct sockaddr_in a1, a2; static void createsocket(unsigned int ip, unsigned short port) { sock = socket(PF_INET, SOCK_STREAM, 0); a2.sin_family = AF_INET; a2.sin_port = htons(port); a2.sin_addr.s_addr = htonl(ip); if( bind(sock, (struct sockaddr*)&a2, sizeof(struct sockaddr_in)) == -1 ) { printf("%d: bind() failed: %d\n", __LINE__, errno); sock = -1; return; } } static void *write_loop(void *arg) { static char writebuffer[1025]; writebuffer[1024] = '\0'; while( writer_active ) { printf("> "); fgets(writebuffer, 1024, stdin); if( feof(stdin) ) break; send(sock, writebuffer, strlen(writebuffer), 0); /* send() probably won't fail, since it's more likely in a chat situation that recv fails (because writer terminates connection first) rather than send fails (reader terminate in middle of receive). */ } writer_active = 0; return NULL; } static void message_loop(int sock) { static char readbuffer[1025]; fd_set sset, rset; pthread_t wthread; struct timeval timeout; int size; writer_active = 1; pthread_create(&wthread, NULL, write_loop, NULL); /* We only have two threads in this process, so threads will probably be created successfully. */ FD_ZERO(&sset); FD_SET(sock, &sset); while( writer_active ) { memcpy(&rset, &sset, sizeof(fd_set)); timeout.tv_sec = 1; timeout.tv_usec = 0; select(FD_SETSIZE, &rset, NULL, NULL, &timeout); /* select() rarely fails */ if( FD_ISSET(sock, &rset) ) { size = recv(sock, readbuffer, 1024, 0); if( size <= 0 ) { writer_active = 0; return; } readbuffer[size] = '\0'; printf("\r \r%s> ", readbuffer); fflush(stdout); } } } int main(int argc, char **argv) { struct hostent *hostinfo; unsigned short port; fd_set sset; socklen_t size; if( argc < 3 ) return printf("%s \n", *argv); if( (hostinfo = gethostbyname(argv[1])) == NULL ) { if( (a1.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE ) return printf("%d: inet_addr() failed: %d\n", __LINE__, errno); } else { a1.sin_addr = *(struct in_addr*)hostinfo->h_addr; } a1.sin_family = AF_INET; a1.sin_port = htons(port = (unsigned short)atoi(argv[2])); createsocket(INADDR_ANY, 0); if( sock == -1 ) return 1; if( connect(sock, (struct sockaddr*)&a1, sizeof(struct sockaddr_in)) == -1 ) { close(sock); createsocket(INADDR_ANY, port); if( sock == -1 ) return 1; if( listen(sock, 1) == -1 ) { close(sock); return printf("%d: listen() failed: %d\n", __LINE__, errno); } FD_ZERO(&sset); FD_SET(sock, &sset); select(FD_SETSIZE, &sset, NULL, NULL, NULL); /* select() rarely fails */ size = sizeof(struct sockaddr_in); s2 = accept(sock, (struct sockaddr*)&a1, &size); close(sock); if( s2 == -1 ) return printf("%d: accept() failed: %d\n", __LINE__, errno); size = sizeof(struct sockaddr_in); getpeername(s2, (struct sockaddr*)&a1, &size); /* getpeername() rarely fails */ printf("Server: accepted connection from %s:%hd\n", inet_ntoa(a1.sin_addr), ntohs(a1.sin_port)); sock = s2; } else { printf("Client: connected to %s:%hd\n", inet_ntoa(a1.sin_addr), ntohs(a1.sin_port)); } message_loop(sock); shutdown(sock, 2); close(sock); putchar('\n'); return 0; }