1 /* ttt.c - client-server tic-tac-toe game
3 * Copyright © 2005 Carl Worth
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * Author: Carl Worth <cworth@cworth.org>
25 _sockaddr_init (struct sockaddr_in *addr,
29 struct hostent *hostent;
30 struct servent *servent;
35 addr->sin_family = AF_INET;
37 hostent = gethostbyname (host);
40 fprintf (stderr, "Error: Lookup failed for host %s: %s\n",
41 host, hstrerror (h_errno));
42 return TTT_STATUS_FAILURE;
44 memcpy (&addr->sin_addr.s_addr, hostent->h_addr_list[0],
45 sizeof (addr->sin_addr.s_addr));
47 assert (*port != '\0');
48 port_long = strtol (port, &endptr, 10);
52 if (port_long <= 0 || port_long >= (1 << 16)) {
53 fprintf (stderr, "Error: Port %ld out of range.\n", port_long);
54 return TTT_STATUS_FAILURE;
56 port_short = port_long;
57 addr->sin_port = htons (port_short);
60 servent = getservbyname (port, "tcp");
62 fprintf (stderr, "Error: Lookup failed for port %s: %s\n",
63 port, hstrerror (h_errno));
64 return TTT_STATUS_FAILURE;
66 addr->sin_port = servent->s_port;
69 return TTT_STATUS_SUCCESS;
73 _wait_for_connection (int listen_socket)
81 FD_SET (listen_socket, &read_set);
84 num_selected = select (listen_socket + 1,
85 &read_set, NULL, NULL,
88 flags = fcntl (listen_socket, F_GETFL);
90 xfcntl (listen_socket, F_SETFL, flags);
92 connected_socket = accept (listen_socket, 0, 0);
96 xfcntl (listen_socket, F_SETFL, flags);
98 if (connected_socket != -1)
99 return connected_socket;
101 if (err == EWOULDBLOCK || err == EAGAIN)
104 fprintf (stderr, "Error: accept failed: %s. Aborting.\n",
110 static const char *WELCOME_MESSAGE =
111 "Welcome to ttt-server. So far, this program is simply a demonstration\n"
112 "of a one-shot TCP/IP server. The server is currently listening on:\n"
114 "\nTo test this program, simply connect a client to that host and port.\n"
117 "\nOnce you have connected a client, the server will echo any characters\n"
118 "it receives back to the client as well as to stdout.\n"
119 "\nNote that to terminate the telnet client you type Control-], then\n"
120 "<Enter>, then \"close\" (and <Enter>) at the \"telnet> \" prompt.\n"
123 "\nPS. By one-shot, I mean that the server will only accept a connection\n"
124 "from a single client, and the server will exit when that client disconnects\n"
125 "To test the server again, you will need to manually restart it again.\n"
126 "Extending the server to start listening again, or to handle multiple\n"
127 "clients simultaneously would both be fun projects for a motivated\n"
128 "student (as would writing a custom client program).\n\n";
131 main (int argc, char **argv)
134 int listen_socket, connected_socket;
135 struct sockaddr_in addr;
137 ttt_args_parse (&args, argc, argv);
140 stderr = xfreopen (args.log_file, "a", stderr);
142 listen_socket = xsocket (PF_INET, SOCK_STREAM, 0);
144 _sockaddr_init (&addr, args.host, args.port);
149 setsockopt (listen_socket, SOL_SOCKET,
150 SO_REUSEADDR, (char *) &one, sizeof (int));
154 xbind (listen_socket, (struct sockaddr *) &addr, sizeof (addr));
156 xlisten (listen_socket, SOMAXCONN);
158 printf (WELCOME_MESSAGE, args.host, args.port, args.host, args.port);
160 connected_socket = _wait_for_connection (listen_socket);
162 #define BUF_SIZE 1024
167 cnt = read (connected_socket, buf, BUF_SIZE);
171 write (connected_socket, buf, cnt);