BRL-CAD
client.c
Go to the documentation of this file.
1 /* C L I E N T . 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/client.c
21  *
22  * Relatively simple example file transfer program using libpkg,
23  * written in a ttcp style.
24  *
25  */
26 
27 #include "common.h"
28 
29 /* system headers */
30 #include <stdlib.h>
31 #include <signal.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include "bio.h"
35 
36 /* interface headers */
37 #include "bu/log.h"
38 #include "bu/malloc.h"
39 #include "bu/getopt.h"
40 #include "bu/file.h"
41 #include "pkg.h"
42 #include "ntp.h"
43 
44 /* used by the client to pass the dbip and opened transfer file
45  * descriptor.
46  */
47 typedef struct _my_data_ {
49  const char *server;
50  int port;
51 } my_data;
52 
53 
54 /**
55  * print a usage statement when invoked with bad, help, or no arguments
56  */
57 static void
58 usage(const char *msg, const char *argv0)
59 {
60  if (msg) {
61  bu_log("%s\n", msg);
62  }
63  bu_log("Client Usage: %s [-p#] [host] file\n\t-p#\tport number to send to (default 2000)\n\thost\thostname or IP address of receiving server\n\tfile\tsome file to transfer\n", argv0 ? argv0 : MAGIC_ID);
64 
65  bu_log("\n%s", pkg_version());
66 
67  exit(1);
68 }
69 
70 /**
71  * simple "valid" port number check used by client and server
72  */
73 static void
74 validate_port(int port) {
75  if (port < 0 || port > 0xffff) {
76  bu_bomb("Invalid negative port range\n");
77  }
78 }
79 
80 /**
81  * callback when a HELO message packet is received.
82  *
83  * We should not encounter this packet specifically since we listened
84  * for it before beginning processing of packets as part of a simple
85  * handshake setup.
86  */
87 void
88 server_helo(struct pkg_conn *UNUSED(connection), char *buf)
89 {
90  bu_log("Unexpected HELO encountered\n");
91  free(buf);
92 }
93 
94 
95 /**
96  * callback when a DATA message packet is received
97  */
98 void
99 server_data(struct pkg_conn *UNUSED(connection), char *buf)
100 {
101  bu_log("Received file data\n");
102  free(buf);
103 }
104 
105 
106 /**
107  * callback when a CIAO message packet is received
108  */
109 void
110 server_ciao(struct pkg_conn *UNUSED(connection), char *buf)
111 {
112  bu_log("CIAO encountered\n");
113  free(buf);
114 }
115 
116 
117 /**
118  * start up a client that connects to the given server, and sends
119  * serialized file data.
120  */
121 void
122 run_client(const char *server, int port, const char *file)
123 {
124  my_data stash;
125  char s_port[MAX_DIGITS + 1] = {0};
126  long bytes = 0;
127  FILE *fp = (FILE *)NULL;
128  int pkg_result = 0;
129  static const unsigned int TPKG_BUFSIZE = 2048;
130  char *buffer;
131  /** our callbacks for each message type */
132  struct pkg_switch callbacks[] = {
133  {MSG_HELO, server_helo, "HELO", NULL},
134  {MSG_DATA, server_data, "DATA", NULL},
135  {MSG_CIAO, server_ciao, "CIAO", NULL},
136  {0, 0, (char *)0, (void*)0}
137  };
138 
139  buffer = (char *)bu_calloc(TPKG_BUFSIZE, 1, "buffer allocation");
140 
141  /* make sure the file can be opened */
142  fp = fopen(file, "rb");
143  if (fp == NULL) {
144  bu_log("Unable to open %s\n", file);
145  bu_bomb("Unable to read file\n");
146  }
147 
148  /* open a connection to the server */
149  validate_port(port);
150 
151  snprintf(s_port, MAX_DIGITS, "%d", port);
152  stash.connection = pkg_open(server, s_port, "tcp", NULL, NULL, NULL, NULL);
153  if (stash.connection == PKC_ERROR) {
154  bu_log("Connection to %s, port %d, failed.\n", server, port);
155  bu_bomb("ERROR: Unable to open a connection to the server\n");
156  }
157  stash.server = server;
158  stash.port = port;
159  stash.connection->pkc_switch = callbacks;
160 
161 
162  /* let the server know we're cool. */
163  bytes = pkg_send(MSG_HELO, MAGIC_ID, strlen(MAGIC_ID) + 1, stash.connection);
164  if (bytes < 0) {
165  pkg_close(stash.connection);
166  bu_log("Connection to %s, port %d, seems faulty.\n", server, port);
167  bu_bomb("ERROR: Unable to communicate with the server\n");
168  }
169 
170 
171  /* Server should have a file to send us.
172  */
173  bu_log("Processing data from server\n");
174  do {
175  /* process packets potentially received in a processing callback */
176  pkg_result = pkg_process(stash.connection);
177  if (pkg_result < 0) {
178  bu_log("Unable to process packets? Weird.\n");
179  } else {
180  bu_log("Processed %d packet%s\n", pkg_result, pkg_result == 1 ? "" : "s");
181  }
182 
183  /* suck in data from the network */
184  pkg_result = pkg_suckin(stash.connection);
185  if (pkg_result < 0) {
186  bu_log("Seemed to have trouble sucking in packets.\n");
187  break;
188  } else if (pkg_result == 0) {
189  bu_log("Client closed the connection.\n");
190  break;
191  }
192 
193  /* process new packets received */
194  pkg_result = pkg_process(stash.connection);
195  if (pkg_result < 0) {
196  bu_log("Unable to process packets? Weird.\n");
197  } else {
198  bu_log("Processed %d packet%s\n", pkg_result, pkg_result == 1 ? "" : "s");
199  }
200  bu_log("buffer: %s\n", stash.connection->pkc_inbuf);
201  } while (stash.connection->pkc_type != MSG_CIAO);
202 
203  /* print the CIAO message */
204  bu_log("buffer: %s\n", stash.connection->pkc_inbuf);
205 
206  /* let the server know we're done. */
207  bytes = pkg_send(MSG_CIAO, "BYE", 4, stash.connection);
208  if (bytes < 0) {
209  bu_log("Unable to cleanly disconnect from %s, port %d.\n", server, port);
210  }
211 
212  /* flush output and close */
213  pkg_close(stash.connection);
214  fclose(fp);
215  bu_free(buffer, "buffer release");
216 
217  return;
218 }
219 
220 
221 /**
222  * main application for both the client and server
223  */
224 int
225 main(int argc, char *argv[]) {
226  const char * const argv0 = argv[0];
227  int c;
228  int port = 2000;
229 
230  /* client stuff */
231  const char *server_name = NULL;
232  const char *file = NULL;
233 
234  /* process the command-line arguments after the application name */
235  while ((c = bu_getopt(argc, argv, "p:P:hH?")) != -1) {
236  if (bu_optopt == '?') c='h';
237  switch (c) {
238  case 'p':
239  case 'P':
240  port = atoi(bu_optarg);
241  break;
242  case 'h':
243  case 'H':
244  /* help */
245  usage(NULL, argv0);
246  break;
247  default:
248  usage("ERROR: Unknown argument\n", argv0);
249  }
250  }
251 
252  argc -= bu_optind;
253  argv += bu_optind;
254 
255 
256  /* prep up the client */
257  if (argc < 1) {
258  usage("ERROR: Missing file argument\n", argv0);
259  } else if (argc > 2) {
260  usage("ERROR: Too many arguments provided\n", argv0);
261  }
262 
263  if (argc < 2) {
264  server_name = "127.0.0.1";
265  } else {
266  server_name = *argv++;
267  }
268  file = *argv++;
269 
270  /* make sure the file exists */
271  if (!bu_file_exists(file, NULL)) {
272  bu_log("File does not exist: %s\n", file);
273  return 1;
274  }
275 
276  /* fire up the client */
277  bu_log("Connecting to %s, port %d\n", server_name, port);
278  run_client(server_name, port, file);
279 
280  return 0;
281 }
282 
283 /*
284  * Local Variables:
285  * mode: C
286  * tab-width: 8
287  * indent-tabs-mode: t
288  * c-file-style: "stroustrup"
289  * End:
290  * ex: shiftwidth=4 tabstop=8
291  */
const struct pkg_switch * pkc_switch
Array of message handlers.
Definition: pkg.h:81
#define MAGIC_ID
Definition: ntp.h:32
char * pkc_inbuf
input stream buffer
Definition: pkg.h:92
struct pkg_conn * connection
Definition: client.c:48
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
void pkg_close(struct pkg_conn *pc)
Definition: pkg.c:800
const char * server
Definition: client.c:49
int port
Definition: client.c:50
char * bu_optarg
Definition: globals.c:91
Header file for the BRL-CAD common definitions.
int bu_optind
Definition: globals.c:89
int pkg_process(struct pkg_conn *)
Definition: pkg.c:1560
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
struct pkg_conn * pkg_open(const char *host, const char *service, const char *protocol, const char *username, const char *passwd, const struct pkg_switch *switchp, pkg_errlog errlog)
unsigned short pkc_type
pkg_type, in host order
Definition: pkg.h:85
void server_data(struct pkg_conn *connection, char *buf)
Definition: client.c:99
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
#define UNUSED(parameter)
Definition: common.h:239
struct _my_data_ my_data
void run_client(const char *server, int port, const char *file)
Definition: client.c:122
Definition: pkg.h:57
const char * pkg_version(void)
Definition: vers.c:31
int main(int argc, char *argv[])
Definition: client.c:225
#define MSG_CIAO
Definition: ntp.h:35
void server_ciao(struct pkg_conn *connection, char *buf)
Definition: client.c:110
#define MAX_DIGITS
Definition: ntp.h:38
Definition: pkg.h:79
int pkg_suckin(struct pkg_conn *)
Definition: pkg.c:1715
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define MSG_HELO
Definition: ntp.h:33
void server_helo(struct pkg_conn *connection, char *buf)
Definition: client.c:88
#define MSG_DATA
Definition: ntp.h:34
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
int bu_file_exists(const char *path, int *fd)
Definition: file.c:57
#define PKC_ERROR
Definition: pkg.h:104