windows/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 
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <winsock2.h>
44 #include "SysCSStream.hpp"
45 #include "ServiceException.hpp"
46 
47 /**
48  * Read from the connection.
49  *
50  * @param buf Target buffer for the read operation.
51  * @param bufsize Size of the target buffer.
52  * @param bytesread Number of bytes actually read.
53  *
54  * @return True on an error, otherwise false
55  */
56 bool SysSocketConnection::read(void *buf, size_t bufsize, size_t *bytesread)
57 {
58  if (c == -1)
59  {
61  return false;
62  }
63  int actual = recv(c, (char *)buf, (int)bufsize, 0);
64  if (actual == -1)
65  {
66  // a -1 return is a bad problem. 0 might be bad, but allow the
67  // caller to handle that one.
69  return false;
70  }
71  *bytesread = (size_t)actual;
73  return true;
74 }
75 
76 
77 /**
78  * Write a buffer to the connection.
79  *
80  * @param buf Source buffer for the write operation.
81  * @param bufsize Size of the source buffer.
82  * @param byteswritten
83  * Number of bytes actually written to the connection.
84  *
85  * @return True on an error, otherwise false
86  */
87 bool SysSocketConnection::write(void *buf, size_t bufsize, size_t *byteswritten)
88 {
89  if (c == -1)
90  {
92  return false;
93  }
94  int actual = send(c, (char *)buf, (int)bufsize, 0);
95  if (actual == -1)
96  {
97  // a -1 return is a bad problem. 0 might be bad, but allow the
98  // caller to handle that one.
100  return false;
101  }
102  *byteswritten = (size_t)actual;
104  return true;
105 }
106 
107 
108 /**
109  * Write a multi-buffer message to the connection.
110  *
111  * @param buf Source buffer for the write operation.
112  * @param bufsize Size of the source buffer.
113  * @param byteswritten
114  * Number of bytes actually written to the connection.
115  *
116  * @return True on an error, otherwise false
117  */
118 bool SysSocketConnection::write(void *buf, size_t bufsize, void *buf2, size_t buf2size, size_t *byteswritten)
119 {
120  // if the second buffer is of zero size, we can handle without
121  // copying
122  if (buf2size == 0)
123  {
124  return write(buf, bufsize, byteswritten);
125  }
126 
127  if (c == -1)
128  {
130  return false;
131  }
132 
133  size_t bufferSize = bufsize + buf2size;
134 
135  // get a buffer large enough for both buffer
136  char *buffer = getMessageBuffer(bufferSize);
137  // if we can't get a buffer, then try sending this in pieces
138  if (buffer == NULL)
139  {
140  // write the first buffer
141  if (!write(buf, bufsize, byteswritten))
142  {
143  return false;
144  }
145  size_t buf2written = 0;
146  if (!write(buf2, buf2size, &buf2written))
147  {
148  return false;
149  }
150  *byteswritten += buf2written;
151  return true;
152  }
153 
154  // copy the message and attached data into a single buffer
155  memcpy(buffer, buf, bufsize);
156  memcpy(buffer + bufsize, buf2, buf2size);
157 
158  int actual = send(c, buffer, (int)bufferSize, 0);
159  // we're done with the buffer, regardless of whether this works or fails
160  returnMessageBuffer(buffer);
161  if (actual == -1)
162  {
163  // a -1 return is a bad problem. 0 might be bad, but allow the
164  // caller to handle that one.
166  return false;
167  }
168  *byteswritten = (size_t)actual;
170  return true;
171 }
172 
173 /**
174  * Get a buffer for sending a buffered message.
175  *
176  * @param size The required size.
177  *
178  * @return A pointer to a buffer, or NULL if unable to allocate.
179  */
180 char *SysSocketConnection::getMessageBuffer(size_t size)
181 {
182  // if larger than our cached buffer, return
183  if (size > MAX_CACHED_BUFFER)
184  {
185  char *buffer = (char *)malloc(size);
186  if (buffer == NULL)
187  {
188  throw new ServiceException(SERVER_FAILURE, "Error allocating message buffer");
189  }
190  return buffer;
191  }
192  // use our cached buffer, allocating it if required.
193  if (messageBuffer == NULL)
194  {
195  messageBuffer = (char *)malloc(MAX_CACHED_BUFFER);
196  if (messageBuffer == NULL)
197  {
198  throw new ServiceException(SERVER_FAILURE, "Error allocating message buffer");
199  }
200  }
201  return messageBuffer;
202 }
203 
204 
205 /**
206  * Return a message buffer after sending a message. This will
207  * either cache the buffer, or release it, depending upon
208  * how it was obtained in the first place.
209  *
210  * @param buffer The buffer to release.
211  */
213 {
214  if (buffer != messageBuffer)
215  {
216  free(buffer);
217  }
218 }
219 
220 
221 /**
222  * Standard constructor.
223  */
225 {
226  domain = AF_INET;
227  type = SOCK_STREAM;
228  protocol = 0;
229 }
230 
231 
232 /**
233  * Alternate constructor.
234  *
235  * @param name Hostname and port in the form "hostname:port".
236  */
238 {
239  domain = AF_INET;
240  type = SOCK_STREAM;
241  protocol = 0;
242  open(name);
243 }
244 
245 
246 /**
247  * Alternate constructor.
248  *
249  * @param host String name of the host.
250  * @param port Target port number.
251  */
252 SysClientStream::SysClientStream(const char *host, int port) : SysSocketConnection()
253 {
254  domain = AF_INET;
255  type = SOCK_STREAM;
256  protocol = 0;
257  open(host, port);
258 }
259 
260 
261 /**
262  * Standard destructor.
263  */
265 {
266  if (c != -1)
267  {
268  close();
269  }
270 }
271 
272 
273 /**
274  * Open a connection to a host/port.
275  *
276  * @param name Hostname and port in the form "hostname:port".
277  *
278  * @return True on an error, otherwise false.
279  */
280 bool SysClientStream::open(const char *name)
281 {
282  // copy the host name so we can separate the host and port values.
283  char *hostname = strdup(name);
284 
285  char *portstr = strstr(hostname, ":");
286  if (portstr == NULL)
287  {
288  free(hostname);
290  return false;
291  }
292  // split the two pieces with a null terminator.
293  *portstr = '\0';
294  portstr++;
295  int port = atoi(portstr);
296  if (port == 0)
297  {
298  free(hostname);
300  return false;
301  }
302  // do the open and free the temp name value.
303  bool result = open(hostname, port);
304  free(hostname);
305  return result;
306 }
307 
308 
309 /**
310  * Open a connection to a host/port.
311  *
312  * @param host The target host name.
313  * @param port The connection port number.
314  *
315  * @return True on an error, otherwise false.
316  */
317 bool SysClientStream::open(const char *host, int port)
318 {
319  struct sockaddr_in addr; // address structure
320  struct hostent *phe; // pointer to a host entry
321  WSADATA wsaData;
322 
323  // initialize Win sockets
324  if (WSAStartup(MAKEWORD(2,0), &wsaData))
325  {
327  }
328 
329  // get a socket
330  c = socket(domain, type, protocol);
331  if (c == -1)
332  {
334  return false;
335  }
336  // convert the host entry/name to an address
337  phe = gethostbyname(host);
338  if (phe)
339  {
340  memcpy(&addr.sin_addr, phe->h_addr, sizeof(addr.sin_addr));
341  }
342  else
343  {
344  addr.sin_addr.s_addr = inet_addr(host);
345  }
346  if (addr.sin_addr.s_addr == INADDR_NONE)
347  {
349  closesocket(c);
350  return false;
351  }
352  // connect to the remote host
353  addr.sin_family = domain;
354  addr.sin_port = htons(port);
355  if (connect(c, (struct sockaddr *) &addr, sizeof(addr)) == -1)
356  {
358  closesocket(c);
359  return false;
360  }
361 
363  return true;
364 }
365 
366 
367 /**
368  * Close the connection to the host.
369  *
370  * @return True on an error, otherwise false.
371  */
373 {
374  if (c != -1)
375  {
376  closesocket(c);
377  }
378  else
379  {
381  return false;
382  }
383  c = -1;
385  return true;
386 }
387 
388 
389 /**
390  * Standard constructor.
391  */
393 {
395  s = -1;
396  domain = AF_INET;
397  type = SOCK_STREAM;
398  protocol = 0;
399  backlog = 20;
400 }
401 
402 
403 /**
404  * Alternate constructor.
405  *
406  * @param name Hostname and port in the form "hostname:port".
407  */
408 SysServerStream::SysServerStream(const char *name)
409 {
411  s = -1;
412  domain = AF_INET;
413  type = SOCK_STREAM;
414  protocol = 0;
415  backlog = 20;
416  make(name);
417 }
418 
419 
420 /**
421  * Alternate constructor.
422  *
423  * @param port Port number to listen on.
424  */
426 {
428  s = -1;
429  domain = AF_INET;
430  type = SOCK_STREAM;
431  protocol = 0;
432  backlog = 20;
433  make(port);
434 }
435 
436 
437 /**
438  * Standard destructor.
439  */
441 {
442  // close our server connection.
443  close();
444 }
445 
446 
447 /**
448  * Make a sever connection.
449  *
450  * @param name Hostname and port in the form "hostname:port".
451  *
452  * @return True on an error, otherwise false
453  */
454 bool SysServerStream::make(const char *name)
455 {
456  char *hostname;
457  char *portstr;
458  int port;
459 
460  // get host name and port strings
461  hostname = strdup(name);
462  portstr = strstr(hostname, ":");
463  if (portstr == NULL)
464  {
465  free(hostname);
467  return false;
468  }
469  *portstr = '\0';
470  portstr++;
471  port = atoi(portstr);
472  free(hostname);
473  if (port == 0)
474  {
476  return false;
477  }
478  return make(port);
479 }
480 
481 
482 /**
483  * Make a server connection.
484  *
485  * @param port Port to use for the connection.
486  *
487  * @return True on an error, otherwise false
488  */
489 bool SysServerStream::make(int port)
490 {
491  struct sockaddr_in addr; // address structure
492  int so_reuseaddr = true; // socket reuse flag
493  WSADATA wsaData;
494 
495  // initialize Win sockets
496  if (WSAStartup(MAKEWORD(2,0), &wsaData))
497  {
499  }
500  // get a server socket
501  s = socket(domain, type, protocol);
502  if (s == -1)
503  {
505  return false;
506  }
507  // set the socket option to reuse the address
508  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&so_reuseaddr,
509  sizeof(so_reuseaddr));
510  // bind the server socket to a port
511  memset(&addr, 0, sizeof (addr));
512  addr.sin_family = domain;
513  addr.sin_port = htons(port);
514 // addr.sin_addr.s_addr = INADDR_ANY;
515  // The following replaces the line above. It forces the socket to be bound
516  // to the local interface only. Thus only the local machine will be allowed
517  // to connect to this socket.
518  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
519  if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) == -1)
520  {
522  return false;
523  }
524  // listen for a client at the port
525  if (listen(s, backlog) == -1)
526  {
528  return false;
529  }
530 
532  return true;
533 }
534 
535 
536 /**
537  * Accept a connection from a client.
538  *
539  * @return True on an error, otherwise false
540  */
542 {
543  struct sockaddr_in addr; // address structure
544  int sz = sizeof(addr);
545 
546  if (s == -1)
547  {
549  return NULL;
550  }
551  SOCKET client = accept(s, (struct sockaddr *) &addr, &sz);
552  if (client == -1)
553  {
555  return NULL;
556  }
557 
559  return new SysServerConnection(this, client);
560 }
561 
562 
563 /**
564  * Close the server connection.
565  *
566  * @return True on an error, otherwise false
567  */
569 {
570  if (s != -1)
571  {
572  closesocket(s);
573  s = -1;
574  }
575  else
576  {
578  return false;
579  }
581  return true;
582 }
583 
584 
585 /**
586  * Server connection constructor.
587  *
588  * @param s The parent server connection.
589  * @param socket The socket for the connection.
590  */
592 {
593  server = s;
594 }
595 
596 /**
597  * Standard destructor.
598  */
600 {
601  disconnect();
602 }
603 
604 
605 /**
606  * Is the connection with the localhost?
607  *
608  *
609  * @return True if the client is at address 127.0.0.1, otherwise false
610  */
612 {
613  sockaddr_in addr;
614  int rc;
615 
616  if (c == -1)
617  {
618  return false;
619  }
620  int nameLen = sizeof(addr);
621  rc = getpeername(c, (struct sockaddr *)&addr, &nameLen);
622  if (rc)
623  {
624  return false;
625  }
626  if (strcmp("127.0.0.1", inet_ntoa(addr.sin_addr)) != 0)
627  {
628  return false;
629  }
630  return true;
631 }
632 
633 
634 /**
635  * Close the server connection.
636  *
637  * @return True on an error, otherwise false
638  */
640 {
641  if (c != -1)
642  {
643  closesocket(c);
644  c = -1;
645  }
646  else
647  {
649  return false;
650  }
652  return true;
653 }
@ 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)
int type
Definition: cmdparse.cpp:383
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