| 1 | /* |
|---|
| 2 | ..Server program that makes a connection for a byte stream socket in the Internet namespace. |
|---|
| 3 | ..Once it has connected to the server, it sends a text string to the server and gets the response. |
|---|
| 4 | Returns 0 or a negative error value. |
|---|
| 5 | */ |
|---|
| 6 | /* |
|---|
| 7 | 16.9.7 Byte Stream Connection Server Example |
|---|
| 8 | The server end is much more complicated. Since we want to allow multiple clients to be connected to the server at the same time, it would be incorrect to wait for input from a single client by simply calling read or recv. Instead, the right thing to do is to use select (see Waiting for I/O) to wait for input on all of the open sockets. This also allows the server to deal with additional connection requests. |
|---|
| 9 | This particular server doesn't do anything interesting once it has gotten a message from a client. It does close the socket for that client when it detects an end-of-file condition (resulting from the client shutting down its end of the connection). |
|---|
| 10 | This program uses make_socket to set up the socket address; see Inet Example. |
|---|
| 11 | */ |
|---|
| 12 | |
|---|
| 13 | #ifndef CISIS_H |
|---|
| 14 | #define GEN_MAIN 1 |
|---|
| 15 | #endif |
|---|
| 16 | |
|---|
| 17 | #if GEN_MAIN |
|---|
| 18 | #include <stdio.h> |
|---|
| 19 | #include <errno.h> |
|---|
| 20 | #include <stdlib.h> |
|---|
| 21 | #include <unistd.h> |
|---|
| 22 | #include <sys/types.h> |
|---|
| 23 | #endif /* GEN_MAIN */ |
|---|
| 24 | |
|---|
| 25 | #include <sys/socket.h> |
|---|
| 26 | #include <netinet/in.h> |
|---|
| 27 | #include <netdb.h> |
|---|
| 28 | #include <time.h> |
|---|
| 29 | |
|---|
| 30 | #if GEN_MAIN |
|---|
| 31 | #define PORT 1417 |
|---|
| 32 | #define BUFFERSIZE 51200 |
|---|
| 33 | #endif /* GEN_MAIN */ |
|---|
| 34 | |
|---|
| 35 | #define REPLYSIZE 51200 |
|---|
| 36 | |
|---|
| 37 | |
|---|
| 38 | int mainserver_make_socket (int cmd, uint16_t port); |
|---|
| 39 | int mainserver_read_from_client (int cmd, uint16_t port, int filedes, char *buffer, int buffersize); |
|---|
| 40 | int mainserver_write_to_client (int cmd, uint16_t port, int filedes, char *message, int messagesize); |
|---|
| 41 | int mainserver (int cmd, uint16_t port, char *buffer, int buffersize, int maxconnqueued); |
|---|
| 42 | |
|---|
| 43 | |
|---|
| 44 | |
|---|
| 45 | /* |
|---|
| 46 | */ |
|---|
| 47 | int |
|---|
| 48 | mainserver_make_socket (int cmd, uint16_t port) |
|---|
| 49 | { |
|---|
| 50 | int sock; |
|---|
| 51 | struct sockaddr_in name; |
|---|
| 52 | |
|---|
| 53 | /* Create the socket. */ |
|---|
| 54 | sock = socket (PF_INET, SOCK_STREAM, 0); |
|---|
| 55 | if (sock < 0) |
|---|
| 56 | { |
|---|
| 57 | /*perror ("socket"); exit (EXIT_FAILURE);*/ |
|---|
| 58 | return -1; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | /* Give the socket a name. */ |
|---|
| 62 | name.sin_family = AF_INET; |
|---|
| 63 | name.sin_port = htons (port); |
|---|
| 64 | name.sin_addr.s_addr = htonl (INADDR_ANY); |
|---|
| 65 | if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) |
|---|
| 66 | { |
|---|
| 67 | /*perror ("bind"); exit (EXIT_FAILURE);*/ |
|---|
| 68 | return -2; |
|---|
| 69 | } |
|---|
| 70 | |
|---|
| 71 | return sock; |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | |
|---|
| 75 | int |
|---|
| 76 | mainserver_write_to_client (int cmd, uint16_t port, int filedes, char *message, int messagesize) |
|---|
| 77 | { |
|---|
| 78 | int nbytes; |
|---|
| 79 | /* yyyymmdd hh:mm:ss WDAY YDAY */ |
|---|
| 80 | char timestamp[80]; /* 123456789012345678901234 7 8 901 */ |
|---|
| 81 | LONGX secs_now; |
|---|
| 82 | struct tm *tp; |
|---|
| 83 | time(&secs_now); tp=localtime(&secs_now); |
|---|
| 84 | sprintf(timestamp,"%04d%02d%02d %02d%02d%02d %1d %3d", 1900+tp->tm_year,tp->tm_mon+1,tp->tm_mday, tp->tm_hour,tp->tm_min,tp->tm_sec, tp->tm_wday,tp->tm_yday); |
|---|
| 85 | |
|---|
| 86 | if (cmd == 3) fprintf (stderr, "Server [%d] [%d] [%s]: reply message (%d bytes): '%s' \n", port, filedes, timestamp, messagesize, message); |
|---|
| 87 | if (cmd == 2) fprintf (stderr, "Server [%d] [%d] [%s]: reply message (%d bytes) \n", port, filedes, timestamp, messagesize); |
|---|
| 88 | |
|---|
| 89 | nbytes = write (filedes, message, messagesize); |
|---|
| 90 | if (nbytes < messagesize) |
|---|
| 91 | { |
|---|
| 92 | /* Write error */ |
|---|
| 93 | /*perror ("write");*/ |
|---|
| 94 | return -1; |
|---|
| 95 | } |
|---|
| 96 | else |
|---|
| 97 | return nbytes; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | |
|---|
| 101 | int |
|---|
| 102 | mainserver_read_from_client (int cmd, uint16_t port, int filedes, char *buffer, int buffersize) |
|---|
| 103 | { |
|---|
| 104 | int nbytes; |
|---|
| 105 | |
|---|
| 106 | buffer[0]='\0'; |
|---|
| 107 | nbytes = read (filedes, buffer, buffersize-1); |
|---|
| 108 | if (nbytes < 0) |
|---|
| 109 | { |
|---|
| 110 | /* Read error. */ |
|---|
| 111 | /*perror ("read"); exit (EXIT_FAILURE);*/ |
|---|
| 112 | return -2; |
|---|
| 113 | } |
|---|
| 114 | else |
|---|
| 115 | { |
|---|
| 116 | #if TRACER |
|---|
| 117 | char *p=buffer; |
|---|
| 118 | int loop=nbytes; |
|---|
| 119 | fprintf (stderr, "read(%d): ",nbytes); |
|---|
| 120 | for (; loop--; p++) fprintf (stderr, "%c=%02x ",*p,(int)*p); |
|---|
| 121 | fprintf (stderr, "\n"); |
|---|
| 122 | #endif |
|---|
| 123 | /* EOF (nbytes=0) or Data read. */ |
|---|
| 124 | buffer[nbytes]='\0'; |
|---|
| 125 | return nbytes; |
|---|
| 126 | } |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | |
|---|
| 130 | /* |
|---|
| 131 | mainserver |
|---|
| 132 | */ |
|---|
| 133 | int |
|---|
| 134 | mainserver (int cmd, uint16_t port, char *buffer, int buffersize, int maxconnqueued) |
|---|
| 135 | { |
|---|
| 136 | int sock; |
|---|
| 137 | fd_set active_fd_set, read_fd_set; |
|---|
| 138 | int i; |
|---|
| 139 | struct sockaddr_in clientname; |
|---|
| 140 | size_t size; |
|---|
| 141 | int shutdown=0; /* run */ |
|---|
| 142 | /* yyyymmdd hh:mm:ss WDAY YDAY */ |
|---|
| 143 | char timestamp[80]; /* 123456789012345678901234 7 8 901 */ |
|---|
| 144 | LONGX secs_in; |
|---|
| 145 | LONGX secs_now; |
|---|
| 146 | struct tm *tp; |
|---|
| 147 | |
|---|
| 148 | /* Create the socket and set it up to accept connections. */ |
|---|
| 149 | sock = mainserver_make_socket (cmd, port); |
|---|
| 150 | |
|---|
| 151 | time(&secs_now); tp=localtime(&secs_now); secs_in=secs_now; |
|---|
| 152 | sprintf(timestamp,"%04d%02d%02d %02d%02d%02d %1d %3d", 1900+tp->tm_year,tp->tm_mon+1,tp->tm_mday, tp->tm_hour,tp->tm_min,tp->tm_sec, tp->tm_wday,tp->tm_yday); |
|---|
| 153 | |
|---|
| 154 | if (cmd == 3) fprintf (stderr, "Server [%d] [%d] [%s]: got socket \n", port, sock, timestamp); |
|---|
| 155 | |
|---|
| 156 | if (listen (sock, maxconnqueued) < 0) /* <== at most 1 connection queued */ |
|---|
| 157 | { |
|---|
| 158 | /*perror ("listen"); exit (EXIT_FAILURE);*/ |
|---|
| 159 | return -1; |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | /* Initialize the set of active sockets. */ |
|---|
| 163 | FD_ZERO (&active_fd_set); |
|---|
| 164 | FD_SET (sock, &active_fd_set); |
|---|
| 165 | |
|---|
| 166 | while (!shutdown) |
|---|
| 167 | { |
|---|
| 168 | /* Block until input arrives on one or more active sockets. */ |
|---|
| 169 | read_fd_set = active_fd_set; |
|---|
| 170 | if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) |
|---|
| 171 | { |
|---|
| 172 | /*perror ("select"); exit (EXIT_FAILURE);*/ |
|---|
| 173 | return -2; |
|---|
| 174 | } |
|---|
| 175 | /* Service all the sockets with input pending. */ |
|---|
| 176 | for (i = 0; i < FD_SETSIZE; ++i) { |
|---|
| 177 | if (FD_ISSET (i, &read_fd_set)) |
|---|
| 178 | { |
|---|
| 179 | if (i == sock) |
|---|
| 180 | { |
|---|
| 181 | /* Connection request on original socket. */ |
|---|
| 182 | int new; |
|---|
| 183 | size = sizeof (clientname); |
|---|
| 184 | new = accept (sock, |
|---|
| 185 | (struct sockaddr *) &clientname, |
|---|
| 186 | &size); |
|---|
| 187 | if (new < 0) |
|---|
| 188 | { |
|---|
| 189 | /*perror ("accept"); exit (EXIT_FAILURE);*/ |
|---|
| 190 | return -3; |
|---|
| 191 | } |
|---|
| 192 | if (cmd == 3) fprintf (stderr, "Server [%d] [%d] [%s]: connect from host %s, port %hd \n", port, sock, timestamp, inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port)); |
|---|
| 193 | FD_SET (new, &active_fd_set); |
|---|
| 194 | } |
|---|
| 195 | else |
|---|
| 196 | { |
|---|
| 197 | /* Data arriving on an already-connected socket. */ |
|---|
| 198 | int nread = mainserver_read_from_client (cmd, port, i, buffer, buffersize); |
|---|
| 199 | int code; |
|---|
| 200 | char replybuf[REPLYSIZE]; |
|---|
| 201 | char *reply=replybuf; |
|---|
| 202 | replybuf[0]='\0'; |
|---|
| 203 | |
|---|
| 204 | time(&secs_now); tp=localtime(&secs_now); |
|---|
| 205 | sprintf(timestamp,"%04d%02d%02d %02d%02d%02d %1d %3d", 1900+tp->tm_year,tp->tm_mon+1,tp->tm_mday, tp->tm_hour,tp->tm_min,tp->tm_sec, tp->tm_wday,tp->tm_yday); |
|---|
| 206 | |
|---|
| 207 | if (cmd == 3) fprintf (stderr, "Server [%d] [%d] [%s]: got message (%d bytes): '%s' \n", port, sock, timestamp, nread, buffer); |
|---|
| 208 | |
|---|
| 209 | if (strlen(buffer) == 0) { reply="server4 100 eof msg\n"; /* never */ code=100; } |
|---|
| 210 | else |
|---|
| 211 | if (strcmp(buffer,"\n") == 0) { reply="server4 101 null msg\n"; code=101; } |
|---|
| 212 | else |
|---|
| 213 | if (strcmp(buffer+nread-1,"\n") != 0) { reply="server4 505 bad msg\n"; code=500; } |
|---|
| 214 | else |
|---|
| 215 | if (strcmp(buffer,"shutdown\n") == 0) { reply="server4 200 thanks\n"; code=0; shutdown=1; } |
|---|
| 216 | else |
|---|
| 217 | if (strcmp(buffer,"hello\n") == 0) { reply="server4 200 hi\n"; code=200; } |
|---|
| 218 | else |
|---|
| 219 | if (strncmp(buffer,"echo ",5) == 0) { sprintf(reply,"server4 200 %s\n",buffer+5); reply=replybuf; code=200; } |
|---|
| 220 | else |
|---|
| 221 | { reply="server4 404 invalid msg\n"; code=400; } |
|---|
| 222 | |
|---|
| 223 | /* Response */ |
|---|
| 224 | if (strlen(reply) > 0) { |
|---|
| 225 | int nbytes=strlen(reply); |
|---|
| 226 | nbytes = mainserver_write_to_client (cmd, port, i, reply, nbytes); |
|---|
| 227 | if (nbytes < 0) |
|---|
| 228 | { |
|---|
| 229 | /*perror ("write (client)");*/ |
|---|
| 230 | close (i); |
|---|
| 231 | FD_CLR (i, &active_fd_set); |
|---|
| 232 | /* return -4; */ |
|---|
| 233 | } |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | close (i); |
|---|
| 237 | FD_CLR (i, &active_fd_set); |
|---|
| 238 | |
|---|
| 239 | } /* end data read */ |
|---|
| 240 | |
|---|
| 241 | } /* end if FD_ISSET */ |
|---|
| 242 | |
|---|
| 243 | if (shutdown) break; |
|---|
| 244 | |
|---|
| 245 | } /* end for FD_SETSIZE */ |
|---|
| 246 | } /* end while */ |
|---|
| 247 | |
|---|
| 248 | /* Release the socket. */ |
|---|
| 249 | close (sock); |
|---|
| 250 | |
|---|
| 251 | time(&secs_now); tp=localtime(&secs_now); |
|---|
| 252 | sprintf(timestamp,"%04d%02d%02d %02d%02d%02d %1d %3d", 1900+tp->tm_year,tp->tm_mon+1,tp->tm_mday, tp->tm_hour,tp->tm_min,tp->tm_sec, tp->tm_wday,tp->tm_yday); |
|---|
| 253 | |
|---|
| 254 | if (cmd == 3) fprintf (stderr, "Server [%d] [%d] [%s]: close socket (%ld seconds) \n", port, sock, timestamp,secs_now-secs_in); |
|---|
| 255 | |
|---|
| 256 | return 0; |
|---|
| 257 | |
|---|
| 258 | } /* end of mainserver */ |
|---|
| 259 | |
|---|
| 260 | |
|---|
| 261 | |
|---|
| 262 | |
|---|
| 263 | /* Main |
|---|
| 264 | |
|---|
| 265 | ./server4 3 |
|---|
| 266 | ./server4 3 2>>xlog & |
|---|
| 267 | |
|---|
| 268 | */ |
|---|
| 269 | |
|---|
| 270 | #if GEN_MAIN |
|---|
| 271 | int |
|---|
| 272 | main(int argc, char *argv[]) |
|---|
| 273 | { |
|---|
| 274 | /* calling parameters */ |
|---|
| 275 | int cmd; |
|---|
| 276 | uint16_t port=PORT; |
|---|
| 277 | int rc; |
|---|
| 278 | |
|---|
| 279 | char buffer[BUFFERSIZE]; |
|---|
| 280 | |
|---|
| 281 | if (argc == 1) { |
|---|
| 282 | fprintf(stderr, "server4 0=plain|1=xml|2=tell|3=trace [port%d] \n",PORT); |
|---|
| 283 | exit (EXIT_FAILURE); |
|---|
| 284 | } |
|---|
| 285 | |
|---|
| 286 | cmd=atoi(argv[1]); |
|---|
| 287 | |
|---|
| 288 | if (argc > 2) port=(uint16_t)atoi(argv[2]); |
|---|
| 289 | |
|---|
| 290 | if (cmd >= 3) fprintf(stderr, "server4: %d \n",port); |
|---|
| 291 | |
|---|
| 292 | rc = mainserver(cmd, port, buffer, BUFFERSIZE, 1); |
|---|
| 293 | |
|---|
| 294 | if (rc < 0) { |
|---|
| 295 | if (cmd >= 3) fprintf(stderr, "server4: exit_failure %d \n", rc); |
|---|
| 296 | exit (EXIT_FAILURE); |
|---|
| 297 | } |
|---|
| 298 | |
|---|
| 299 | if (cmd >= 3) fprintf(stderr, "server4: exit_success \n"); |
|---|
| 300 | exit (EXIT_SUCCESS); |
|---|
| 301 | } |
|---|
| 302 | #endif /* GEN_MAIN */ |
|---|
| 303 | |
|---|
| 304 | #undef GEN_MAIN |
|---|
| 305 | |
|---|