unix/SysCSStream.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
4 /* */
5 /* This program and the accompanying materials are made available under */
6 /* the terms of the Common Public License v1.0 which accompanies this */
7 /* distribution. A copy is also available at the following address: */
8 /* http://www.ibm.com/developerworks/oss/CPLv1.0.htm */
9 /* */
10 /* Redistribution and use in source and binary forms, with or */
11 /* without modification, are permitted provided that the following */
12 /* conditions are met: */
13 /* */
14 /* Redistributions of source code must retain the above copyright */
15 /* notice, this list of conditions and the following disclaimer. */
16 /* Redistributions in binary form must reproduce the above copyright */
17 /* notice, this list of conditions and the following disclaimer in */
18 /* the documentation and/or other materials provided with the distribution. */
19 /* */
20 /* Neither the name of Rexx Language Association nor the names */
21 /* of its contributors may be used to endorse or promote products */
22 /* derived from this software without specific prior written permission. */
23 /* */
24 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
25 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
26 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
27 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
28 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
29 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
30 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
31 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
32 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
33 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
34 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
35 /* */
36 /*----------------------------------------------------------------------------*/
37 
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41 
42 #include <string.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <sys/ioctl.h>
52 #include <netdb.h>
53 
54 #if defined( HAVE_STRINGS_H )
55 # include <strings.h>
56 #endif
57 #include <errno.h>
58 #include "SysCSStream.hpp"
59 #include "ServiceException.hpp"
60 
61 /**
62  * Read from the connection.
63  *
64  * @param buf Target buffer for the read operation.
65  * @param bufsize Size of the target buffer.
66  * @param bytesread Number of bytes actually read.
67  *
68  * @return True on an error, otherwise false
69  */
70 bool SysSocketConnection::read(void *buf, size_t bufsize, size_t *bytesread)
71 {
72  if (c == -1)
73  {
75  return false;
76  }
77  int actual = recv(c, (char *)buf, (int)bufsize, 0);
78  if (actual == -1)
79  {
80  // a -1 return is a bad problem. 0 might be bad, but allow the
81  // caller to handle that one.
83  return false;
84  }
85  *bytesread = (size_t)actual;
87  return true;
88 }
89 
90 
91 /**
92  * Write a buffer to the connection.
93  *
94  * @param buf Source buffer for the write operation.
95  * @param bufsize Size of the source buffer.
96  * @param byteswritten
97  * Number of bytes actually written to the connection.
98  *
99  * @return True on an error, otherwise false
100  */
101 bool SysSocketConnection::write(void *buf, size_t bufsize, size_t *byteswritten)
102 {
103  if (c == -1)
104  {
106  return false;
107  }
108  int actual = send(c, (char *)buf, (int)bufsize, 0);
109  if (actual == -1)
110  {
111  // a -1 return is a bad problem. 0 might be bad, but allow the
112  // caller to handle that one.
114  return false;
115  }
116  *byteswritten = (size_t)actual;
118  return true;
119 }
120 
121 
122 /**
123  * Write a multi-buffer message to the connection.
124  *
125  * @param buf Source buffer for the write operation.
126  * @param bufsize Size of the source buffer.
127  * @param byteswritten
128  * Number of bytes actually written to the connection.
129  *
130  * @return True on an error, otherwise false
131  */
132 bool SysSocketConnection::write(void *buf, size_t bufsize, void *buf2, size_t buf2size, size_t *byteswritten)
133 {
134  // if the second buffer is of zero size, we can handle without
135  // copying
136  if (buf2size == 0)
137  {
138  return write(buf, bufsize, byteswritten);
139  }
140 
141  if (c == -1)
142  {
144  return false;
145  }
146 
147  size_t bufferSize = bufsize + buf2size;
148 
149  // get a buffer large enough for both buffer
150  char *buffer = getMessageBuffer(bufferSize);
151  // if we can't get a buffer, then try sending this in pieces
152  if (buffer == NULL)
153  {
154  // write the first buffer
155  if (!write(buf, bufsize, byteswritten))
156  {
157  return false;
158  }
159  size_t buf2written = 0;
160  if (!write(buf2, buf2size, &buf2written))
161  {
162  return false;
163  }
164  *byteswritten += buf2written;
165  return true;
166  }
167 
168  // copy the message and attached data into a single buffer
169  memcpy(buffer, buf, bufsize);
170  memcpy(buffer + bufsize, buf2, buf2size);
171 
172  int actual = send(c, buffer, (int)bufferSize, 0);
173  // we're done with the buffer, regardless of whether this works or fails
174  returnMessageBuffer(buffer);
175  if (actual == -1)
176  {
177  // a -1 return is a bad problem. 0 might be bad, but allow the
178  // caller to handle that one.
180  return false;
181  }
182  *byteswritten = (size_t)actual;
184  return true;
185 }
186 
187 /**
188  * Get a buffer for sending a buffered message.
189  *
190  * @param size The required size.
191  *
192  * @return A pointer to a buffer, or NULL if unable to allocate.
193  */
195 {
196  // if larger than our cached buffer, return
197  if (size > MAX_CACHED_BUFFER)
198  {
199  char *buffer = (char *)malloc(size);
200  if (buffer == NULL)
201  {
202  throw new ServiceException(SERVER_FAILURE, "Error allocating message buffer");
203  }
204  return buffer;
205  }
206  // use our cached buffer, allocating it if required.
207  if (messageBuffer == NULL)
208  {
209  messageBuffer = (char *)malloc(MAX_CACHED_BUFFER);
210  if (messageBuffer == NULL)
211  {
212  throw new ServiceException(SERVER_FAILURE, "Error allocating message buffer");
213  }
214  }
215  return messageBuffer;
216 }
217 
218 
219 /**
220  * Return a message buffer after sending a message. This will
221  * either cache the buffer, or release it, depending upon
222  * how it was obtained in the first place.
223  *
224  * @param buffer The buffer to release.
225  */
227 {
228  if (buffer != messageBuffer)
229  {
230  free(buffer);
231  }
232 }
233 
234 
235 /**
236  * Standard constructor.
237  */
239 {
240  domain = AF_INET;
241  type = SOCK_STREAM;
242  protocol = 0;
243 }
244 
245 
246 /**
247  * Alternate constructor.
248  *
249  * @param name Hostname and port in the form "hostname:port".
250  */
252 {
253  domain = AF_INET;
254  type = SOCK_STREAM;
255  protocol = 0;
256  open(name);
257 }
258 
259 
260 /**
261  * Alternate constructor.
262  *
263  * @param host String name of the host.
264  * @param port Target port number.
265  */
267 {
268  domain = AF_INET;
269  type = SOCK_STREAM;
270  protocol = 0;
271  open(host, port);
272 }
273 
274 
275 /**
276  * Standard destructor.
277  */
279 {
280  if (c != -1)
281  {
282  close();
283  }
284 }
285 
286 
287 /**
288  * Open a connection to a host/port.
289  *
290  * @param name Hostname and port in the form "hostname:port".
291  *
292  * @return True on an error, otherwise false.
293  */
294 bool SysClientStream::open(const char *name)
295 {
296  // copy the host name so we can separate the host and port values.
297  char *hostname = strdup(name);
298 
299  char *portstr = strstr(hostname, ":");
300  if (portstr == NULL)
301  {
302  free(hostname);
304  return false;
305  }
306  // split the two pieces with a null terminator.
307  *portstr = '\0';
308  portstr++;
309  int port = atoi(portstr);
310  if (port == 0)
311  {
312  free(hostname);
314  return false;
315  }
316  // do the open and free the temp name value.
317  bool result = open(hostname, port);
318  free(hostname);
319  return result;
320 }
321 
322 
323 /**
324  * Open a connection to a host/port.
325  *
326  * @param host The target host name.
327  * @param port The connection port number.
328  *
329  * @return True on an error, otherwise false.
330  */
331 bool SysClientStream::open(const char *host, int port)
332 {
333  struct sockaddr_in addr; // address structure
334  struct hostent *phe; // pointer to a host entry
335 
336  // get a socket
337  c = socket(domain, type, protocol);
338  if (c == -1)
339  {
341  return false;
342  }
343  // convert the host entry/name to an address
344  phe = gethostbyname(host);
345  if (phe)
346  {
347  bcopy(phe->h_addr, (char *) &addr.sin_addr, sizeof(addr.sin_addr));
348  }
349  else
350  {
351  addr.sin_addr.s_addr = inet_addr(host);
352  }
353  if (addr.sin_addr.s_addr == INADDR_NONE)
354  {
356  close();
357  return false;
358  }
359  // connect to the remote host
360  addr.sin_family = domain;
361  addr.sin_port = htons(port);
362  if (connect(c, (struct sockaddr *) &addr, sizeof(addr)) == -1)
363  {
365  close();
366  return false;
367  }
368 
370  return true;
371 }
372 
373 
374 /**
375  * Close the connection to the host.
376  *
377  * @return True on an error, otherwise false.
378  */
380 {
381  if (c != -1)
382  {
383  ::close(c);
384  }
385  else
386  {
388  return false;
389  }
390  c = -1;
392  return true;
393 }
394 
395 
396 /**
397  * Standard constructor.
398  */
400 {
402  s = -1;
403  domain = AF_INET;
404  type = SOCK_STREAM;
405  protocol = 0;
406  backlog = 20;
407 }
408 
409 
410 /**
411  * Alternate constructor.
412  *
413  * @param name Hostname and port in the form "hostname:port".
414  */
416 {
418  s = -1;
419  domain = AF_INET;
420  type = SOCK_STREAM;
421  protocol = 0;
422  backlog = 20;
423  make(name);
424 }
425 
426 
427 /**
428  * Alternate constructor.
429  *
430  * @param port Port number to listen on.
431  */
433 {
435  s = -1;
436  domain = AF_INET;
437  type = SOCK_STREAM;
438  protocol = 0;
439  backlog = 20;
440  make(port);
441 }
442 
443 
444 /**
445  * Standard destructor.
446  */
448 {
449  // close our server connection.
450  close();
451 }
452 
453 
454 /**
455  * Make a sever connection.
456  *
457  * @param name Hostname and port in the form "hostname:port".
458  *
459  * @return True on an error, otherwise false
460  */
461 bool SysServerStream::make(const char *name)
462 {
463  char *hostname;
464  char *portstr;
465  int port;
466 
467  // get host name and port strings
468  hostname = strdup(name);
469  portstr = strstr(hostname, ":");
470  if (portstr == NULL)
471  {
472  free(hostname);
474  return false;
475  }
476  *portstr = '\0';
477  portstr++;
478  port = atoi(portstr);
479  free(hostname);
480  if (port == 0)
481  {
483  return false;
484  }
485  return make(port);
486 }
487 
488 
489 /**
490  * Make a server connection.
491  *
492  * @param port Port to use for the connection.
493  *
494  * @return True on an error, otherwise false
495  */
496 bool SysServerStream::make(int port)
497 {
498  struct sockaddr_in addr; // server address structure
499  int so_reuseaddr = false; // socket reuse flag
500 
501  // get a server socket
502  s = socket(domain, type, protocol);
503  if (s == -1)
504  {
506  return false;
507  }
508  // set the socket option to reuse the address
509  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&so_reuseaddr,
510  sizeof(so_reuseaddr));
511  // bind the server socket to a port
512  memset(&addr, 0, sizeof (addr));
513  addr.sin_family = domain;
514  addr.sin_port = htons(port);
515 // addr.sin_addr.s_addr = INADDR_ANY;
516  // The following replaces the line above. It forces the socket to be bound
517  // to the local interface only. Thus only the local machine will be allowed
518  // to connect to this socket.
519  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
520  if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) == -1)
521  {
523  return false;
524  }
525  // listen for a client at the port
526  if (listen(s, backlog) == -1)
527  {
529  return false;
530  }
531 
533  return true;
534 }
535 
536 
537 /**
538  * Accept a connection from a client.
539  *
540  * @return True on an error, otherwise false
541  */
543 {
544  struct sockaddr_in addr; // address structure
545  socklen_t sz = sizeof(addr);
546 
547  if (s == -1)
548  {
550  return NULL;
551  }
552  int c = accept(s, (struct sockaddr *) &addr, &sz);
553  if (c == -1)
554  {
556  return NULL;
557  }
558 
560  return new SysServerConnection(this, c);
561 }
562 
563 
564 /**
565  * Close the server connection.
566  *
567  * @return True on an error, otherwise false
568  */
570 {
571  if (s != -1)
572  {
573  ::close(s);
574  s = -1;
575  }
576  else
577  {
579  return false;
580  }
582  return true;
583 }
584 
585 
586 /**
587  * Server connection constructor.
588  *
589  * @param s The parent server connection.
590  * @param socket The socket for the connection.
591  */
593 {
594  server = s;
595 }
596 
597 /**
598  * Standard destructor.
599  */
601 {
602  disconnect();
603 }
604 
605 
606 /**
607  * Is the connection with the localhost?
608  *
609  *
610  * @return True if the client is at address 127.0.0.1, otherwise false
611  */
613 {
614  sockaddr_in addr;
615  int rc;
616  socklen_t nameLen;
617 
618  if (c == -1)
619  {
620  return false;
621  }
622  nameLen = sizeof(addr);
623  rc = getpeername(c,(struct sockaddr *)&addr,&nameLen);
624  if (rc)
625  {
626  return false;
627  }
628  if (strcmp("127.0.0.1", inet_ntoa(addr.sin_addr)) != 0)
629  {
630  return false;
631  }
632  return true;
633 }
634 
635 
636 /**
637  * Close the connection to the host.
638  *
639  * @return True on an error, otherwise false.
640  */
642 {
643  if (c != -1)
644  {
645  close(c);
646  c = -1;
647  }
648  else
649  {
651  return false;
652  }
654  return true;
655 }
656 
@ SERVER_FAILURE
bool open(const char *)
SysServerStream * server
SysServerConnection(SysServerStream *s, int socket)
CSErrorCodeT errcode
bool make(const char *)
SysServerConnection * connect()
void returnMessageBuffer(void *)
char * getMessageBuffer(size_t size)
bool write(void *buf, size_t bufsize, size_t *byteswritten)
bool read(void *buf, size_t bufsize, size_t *bytesread)
struct sockaddr_in sockaddr_in
Definition: rxsock.h:48
@ CSERROR_CONNX_EXISTS
@ CSERROR_OPEN_FAILED
@ CSERROR_UNKNOWN
@ CSERROR_IO_FAILED
@ CSERROR_HOSTNAME_PORT
@ CSERROR_CONNX_FAILED
@ CSERROR_INTERNAL
@ CSERROR_OK