BRL-CAD
server.c
Go to the documentation of this file.
1 /* S E R V E R . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2006-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file libpkg/example/server.c
21  *
22  * Basic pkg server.
23  *
24  */
25 
26 #include "common.h"
27 
28 /* system headers */
29 #include <stdlib.h>
30 #include <signal.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include "bio.h"
34 
35 /* interface headers */
36 #include "bu/log.h"
37 #include "bu/str.h"
38 #include "bu/malloc.h"
39 #include "bu/getopt.h"
40 #include "pkg.h"
41 #include "ntp.h"
42 
43 /**
44  * print a usage statement when invoked with bad, help, or no arguments
45  */
46 static void
47 usage(const char *msg, const char *argv0)
48 {
49  if (msg) {
50  bu_log("%s\n", msg);
51  }
52  bu_log("Server Usage: %s [-p#]\n\t-p#\tport number to listen on (default 2000)\n", argv0 ? argv0 : MAGIC_ID);
53 
54  bu_log("\n%s", pkg_version());
55 
56  exit(1);
57 }
58 
59 /**
60  * simple "valid" port number check used by client and server
61  */
62 static void
63 validate_port(int port) {
64  if (port < 0 || port > 0xffff) {
65  bu_bomb("Invalid negative port range\n");
66  }
67 }
68 
69 /**
70  * callback when a HELO message packet is received.
71  *
72  * We should not encounter this packet specifically since we listened
73  * for it before beginning processing of packets as part of a simple
74  * handshake setup.
75  */
76 void
77 server_helo(struct pkg_conn *UNUSED(connection), char *buf)
78 {
79  bu_log("Unexpected HELO encountered\n");
80  free(buf);
81 }
82 
83 
84 /**
85  * callback when a DATA message packet is received
86  */
87 void
88 server_data(struct pkg_conn *UNUSED(connection), char *buf)
89 {
90  bu_log("Received file data\n");
91  free(buf);
92 }
93 
94 
95 /**
96  * callback when a CIAO message packet is received
97  */
98 void
99 server_ciao(struct pkg_conn *UNUSED(connection), char *buf)
100 {
101  bu_log("CIAO encountered\n");
102  free(buf);
103 }
104 
105 
106 /**
107  * start up a server that listens for a single client.
108  */
109 void
110 run_server(int port) {
111  struct pkg_conn *client;
112  int netfd;
113  char portname[MAX_DIGITS + 1] = {0};
114  /* int pkg_result = 0; */
115  char *buffer, *msgbuffer;
116  long bytes = 0;
117  FILE *fp;
118 
119  /** our server callbacks for each message type */
120  struct pkg_switch callbacks[] = {
121  {MSG_HELO, server_helo, "HELO", NULL},
122  {MSG_DATA, server_data, "DATA", NULL},
123  {MSG_CIAO, server_ciao, "CIAO", NULL},
124  {0, 0, (char *)0, (void*)0}
125  };
126 
127  validate_port(port);
128 
129  /* start up the server on the given port */
130  snprintf(portname, MAX_DIGITS, "%d", port);
131  netfd = pkg_permserver(portname, "tcp", 0, 0);
132  if (netfd < 0) {
133  bu_bomb("Unable to start the server");
134  }
135 
136  /* listen for a good client indefinitely. this is a simple
137  * handshake that waits for a HELO message from the client. if it
138  * doesn't get one, the server continues to wait.
139  */
140  do {
141  client = pkg_getclient(netfd, callbacks, NULL, 0);
142  if (client == PKC_NULL) {
143  bu_log("Connection seems to be busy, waiting...\n");
144  sleep(10);
145  continue;
146  } else if (client == PKC_ERROR) {
147  bu_log("Fatal error accepting client connection.\n");
148  pkg_close(client);
149  client = PKC_NULL;
150  continue;
151  }
152 
153  /* got a connection, process it */
154  msgbuffer = pkg_bwaitfor (MSG_HELO, client);
155  if (msgbuffer == NULL) {
156  bu_log("Failed to process the client connection, still waiting\n");
157  pkg_close(client);
158  client = PKC_NULL;
159  } else {
160  bu_log("msgbuffer: %s\n", msgbuffer);
161  /* validate magic header that client should have sent */
162  if (!BU_STR_EQUAL(msgbuffer, MAGIC_ID)) {
163  bu_log("Bizarre corruption, received a HELO without at matching MAGIC ID!\n");
164  pkg_close(client);
165  client = PKC_NULL;
166  }
167  }
168  } while (client == PKC_NULL);
169 
170  /* have client, will send file */
171  fp = fopen("lempar.c", "rb");
172  buffer = (char *)bu_calloc(2048, 1, "buffer allocation");
173 
174  if (fp == NULL) {
175  bu_log("Unable to open lempar.c\n");
176  bu_bomb("Unable to read file\n");
177  }
178 
179  /* send the file data to the server */
180  while (!feof(fp) && !ferror(fp)) {
181  bytes = fread(buffer, 1, 2048, fp);
182  bu_log("Read %ld bytes from lempar.c\n", bytes);
183 
184  if (bytes > 0) {
185  bytes = pkg_send(MSG_DATA, buffer, (size_t)bytes, client);
186  if (bytes < 0) {
187  pkg_close(client);
188  bu_log("Unable to successfully send data");
189  bu_free(buffer, "buffer release");
190  return;
191  }
192  }
193  }
194 
195  /* Tell the client we're done */
196  bytes = pkg_send(MSG_CIAO, "DONE", 5, client);
197  if (bytes < 0) {
198  bu_log("Connection to client seems faulty.\n");
199  }
200 
201  /* Confirm the client is done */
202  buffer = pkg_bwaitfor (MSG_CIAO , client);
203  bu_log("buffer: %s\n", buffer);
204 
205  /* shut down the server, one-time use */
206  pkg_close(client);
207 }
208 
209 /**
210  * main application for both the client and server
211  */
212 int
213 main(int argc, char *argv[]) {
214  const char * const argv0 = argv[0];
215  int c;
216  int port = 2000;
217 
218  if (argc > 2) {
219  usage("ERROR: Incorrect number of arguments\n", argv[0]);
220  }
221 
222  /* process the command-line arguments after the application name */
223  while ((c = bu_getopt(argc, argv, "p:P:hH?")) != -1) {
224  if (bu_optopt == '?') c='h';
225  switch (c) {
226  case 'p':
227  case 'P':
228  port = atoi(bu_optarg);
229  break;
230  case 'h':
231  case 'H':
232  /* help */
233  usage(NULL, argv0);
234  break;
235  default:
236  usage("ERROR: Unknown argument\n", argv0);
237  }
238  }
239 
240  argc -= bu_optind;
241  argv += bu_optind;
242 
243  if (argc > 0) {
244  usage("ERROR: Unexpected extra server arguments\n", argv0);
245  }
246 
247  /* ignore broken pipes, on platforms where we have SIGPIPE */
248 #ifdef SIGPIPE
249  (void)signal(SIGPIPE, SIG_IGN);
250 #endif
251 
252  /* fire up the server */
253  bu_log("Listening on port %d\n", port);
254  run_server(port);
255 
256  return 0;
257 }
258 
259 /*
260  * Local Variables:
261  * mode: C
262  * tab-width: 8
263  * indent-tabs-mode: t
264  * c-file-style: "stroustrup"
265  * End:
266  * ex: shiftwidth=4 tabstop=8
267  */
#define MAGIC_ID
Definition: ntp.h:32
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
void pkg_close(struct pkg_conn *pc)
Definition: pkg.c:800
char * bu_optarg
Definition: globals.c:91
Header file for the BRL-CAD common definitions.
int bu_optind
Definition: globals.c:89
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
int main(int argc, char *argv[])
Definition: server.c:213
int pkg_send(int type, const char *buf, size_t len, struct pkg_conn *pc)
Definition: pkg.c:934
int bu_optopt
Definition: globals.c:90
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
void server_ciao(struct pkg_conn *connection, char *buf)
Definition: server.c:99
#define PKC_NULL
Definition: pkg.h:103
void server_helo(struct pkg_conn *connection, char *buf)
Definition: server.c:77
#define UNUSED(parameter)
Definition: common.h:239
Definition: pkg.h:57
const char * pkg_version(void)
Definition: vers.c:31
char * pkg_bwaitfor(int type, struct pkg_conn *pc)
Definition: pkg.c:1448
#define MSG_CIAO
Definition: ntp.h:35
int pkg_permserver(const char *service, const char *protocol, int backlog, pkg_errlog)
#define MAX_DIGITS
Definition: ntp.h:38
Definition: pkg.h:79
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define MSG_HELO
Definition: ntp.h:33
void run_server(int port)
Definition: server.c:110
struct pkg_conn * pkg_getclient(int fd, const struct pkg_switch *switchp, pkg_errlog errlog, int nodelay)
#define MSG_DATA
Definition: ntp.h:34
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
void server_data(struct pkg_conn *connection, char *buf)
Definition: server.c:88
#define PKC_ERROR
Definition: pkg.h:104
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126