MFEM  v3.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
socketstream.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 #ifdef _WIN32
13 // Turn off CRT deprecation warnings for strerror (VS 2013)
14 #define _CRT_SECURE_NO_WARNINGS
15 #endif
16 
17 #include "socketstream.hpp"
18 
19 #include <cstring> // memset, memcpy, strerror
20 #include <cerrno> // errno
21 #ifndef _WIN32
22 #include <netdb.h> // gethostbyname
23 #include <arpa/inet.h> // htons
24 #include <sys/types.h> // socket, setsockopt, connect, recv, send
25 #include <sys/socket.h> // socket, setsockopt, connect, recv, send
26 #include <unistd.h> // close
27 #include <netinet/in.h> // sockaddr_in
28 #define closesocket (::close)
29 #else
30 #include <winsock.h>
31 typedef int ssize_t;
32 // Link with ws2_32.lib
33 #pragma comment(lib, "ws2_32.lib")
34 #endif
35 
36 namespace mfem
37 {
38 
39 int socketbuf::attach(int sd)
40 {
41  int old_sd = socket_descriptor;
42  pubsync();
43  socket_descriptor = sd;
44  setg(NULL, NULL, NULL);
45  setp(obuf, obuf + buflen);
46  return old_sd;
47 }
48 
49 int socketbuf::open(const char hostname[], int port)
50 {
51  struct sockaddr_in sa;
52  struct hostent *hp;
53 
54  close();
55  setg(NULL, NULL, NULL);
56  setp(obuf, obuf + buflen);
57 
58  hp = gethostbyname(hostname);
59  if (hp == NULL)
60  {
61  socket_descriptor = -3;
62  return -1;
63  }
64  memset(&sa, 0, sizeof(sa));
65  memcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length);
66  sa.sin_family = hp->h_addrtype;
67  sa.sin_port = htons(port);
68  socket_descriptor = socket(hp->h_addrtype, SOCK_STREAM, 0);
69  if (socket_descriptor < 0)
70  {
71  return -1;
72  }
73 
74 #if defined __APPLE__
75  // OS X does not support the MSG_NOSIGNAL option of send().
76  // Instead we can use the SO_NOSIGPIPE socket option.
77  int on = 1;
78  if (setsockopt(socket_descriptor, SOL_SOCKET, SO_NOSIGPIPE,
79  (char *)(&on), sizeof(on)) < 0)
80  {
81  closesocket(socket_descriptor);
82  socket_descriptor = -2;
83  return -1;
84  }
85 #endif
86 
87  if (connect(socket_descriptor,
88  (const struct sockaddr *)&sa, sizeof(sa)) < 0)
89  {
90  closesocket(socket_descriptor);
91  socket_descriptor = -2;
92  return -1;
93  }
94  return 0;
95 }
96 
98 {
99  if (is_open())
100  {
101  pubsync();
102  int err = closesocket(socket_descriptor);
103  socket_descriptor = -1;
104  return err;
105  }
106  return 0;
107 }
108 
110 {
111  ssize_t bw, n = pptr() - pbase();
112  // std::cout << "[socketbuf::sync n=" << n << ']' << std::endl;
113  while (n > 0)
114  {
115 #ifdef MSG_NOSIGNAL
116  bw = send(socket_descriptor, pptr() - n, n, MSG_NOSIGNAL);
117 #else
118  bw = send(socket_descriptor, pptr() - n, n, 0);
119 #endif
120  if (bw < 0)
121  {
122 #ifdef MFEM_DEBUG
123  std::cout << "Error in send(): " << strerror(errno) << std::endl;
124 #endif
125  setp(pptr() - n, obuf + buflen);
126  pbump(n);
127  return -1;
128  }
129  n -= bw;
130  }
131  setp(obuf, obuf + buflen);
132  return 0;
133 }
134 
135 socketbuf::int_type socketbuf::underflow()
136 {
137  // assuming (gptr() < egptr()) is false
138  ssize_t br = recv(socket_descriptor, ibuf, buflen, 0);
139  // std::cout << "[socketbuf::underflow br=" << br << ']'
140  // << std::endl;
141  if (br <= 0)
142  {
143 #ifdef MFEM_DEBUG
144  if (br < 0)
145  {
146  std::cout << "Error in recv(): " << strerror(errno) << std::endl;
147  }
148 #endif
149  setg(NULL, NULL, NULL);
150  return traits_type::eof();
151  }
152  setg(ibuf, ibuf, ibuf + br);
153  return traits_type::to_int_type(*ibuf);
154 }
155 
156 socketbuf::int_type socketbuf::overflow(int_type c)
157 {
158  if (sync() < 0)
159  {
160  return traits_type::eof();
161  }
162  if (traits_type::eq_int_type(c, traits_type::eof()))
163  {
164  return traits_type::not_eof(c);
165  }
166  *pptr() = traits_type::to_char_type(c);
167  pbump(1);
168  return c;
169 }
170 
171 std::streamsize socketbuf::xsgetn(char_type *__s, std::streamsize __n)
172 {
173  // std::cout << "[socketbuf::xsgetn __n=" << __n << ']'
174  // << std::endl;
175  const std::streamsize bn = egptr() - gptr();
176  if (__n <= bn)
177  {
178  traits_type::copy(__s, gptr(), __n);
179  gbump(__n);
180  return __n;
181  }
182  traits_type::copy(__s, gptr(), bn);
183  setg(NULL, NULL, NULL);
184  std::streamsize remain = __n - bn;
185  char_type *end = __s + __n;
186  ssize_t br;
187  while (remain > 0)
188  {
189  br = recv(socket_descriptor, end - remain, remain, 0);
190  if (br <= 0)
191  {
192 #ifdef MFEM_DEBUG
193  if (br < 0)
194  {
195  std::cout << "Error in recv(): " << strerror(errno) << std::endl;
196  }
197 #endif
198  return (__n - remain);
199  }
200  remain -= br;
201  }
202  return __n;
203 }
204 
205 std::streamsize socketbuf::xsputn(const char_type *__s, std::streamsize __n)
206 {
207  // std::cout << "[socketbuf::xsputn __n=" << __n << ']'
208  // << std::endl;
209  if (pptr() + __n <= epptr())
210  {
211  traits_type::copy(pptr(), __s, __n);
212  pbump(__n);
213  return __n;
214  }
215  if (sync() < 0)
216  {
217  return 0;
218  }
219  ssize_t bw;
220  std::streamsize remain = __n;
221  const char_type *end = __s + __n;
222  while (remain > buflen)
223  {
224 #ifdef MSG_NOSIGNAL
225  bw = send(socket_descriptor, end - remain, remain, MSG_NOSIGNAL);
226 #else
227  bw = send(socket_descriptor, end - remain, remain, 0);
228 #endif
229  if (bw < 0)
230  {
231 #ifdef MFEM_DEBUG
232  std::cout << "Error in send(): " << strerror(errno) << std::endl;
233 #endif
234  return (__n - remain);
235  }
236  remain -= bw;
237  }
238  if (remain > 0)
239  {
240  traits_type::copy(pptr(), end - remain, remain);
241  pbump(remain);
242  }
243  return __n;
244 }
245 
246 
248 {
249  listen_socket = socket(PF_INET, SOCK_STREAM, 0); // tcp socket
250  if (listen_socket < 0)
251  {
252  return;
253  }
254  int on = 1;
255  if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR,
256  (char *)(&on), sizeof(on)) < 0)
257  {
258  closesocket(listen_socket);
259  listen_socket = -2;
260  return;
261  }
262  struct sockaddr_in sa;
263  memset(&sa, 0, sizeof(sa));
264  sa.sin_family = AF_INET;
265  sa.sin_port = htons(port);
266  sa.sin_addr.s_addr = INADDR_ANY;
267  if (bind(listen_socket, (const struct sockaddr *)&sa, sizeof(sa)))
268  {
269  closesocket(listen_socket);
270  listen_socket = -3;
271  return;
272  }
273  const int backlog = 4;
274  if (listen(listen_socket, backlog) < 0)
275  {
276  closesocket(listen_socket);
277  listen_socket = -4;
278  return;
279  }
280 }
281 
283 {
284  if (!good())
285  {
286  return 0;
287  }
288  int err = closesocket(listen_socket);
289  listen_socket = -1;
290  return err;
291 }
292 
294 {
295  if (!good())
296  {
297  return -1;
298  }
299  int socketd = ::accept(listen_socket, NULL, NULL);
300  if (socketd >= 0)
301  {
302  sockstr.rdbuf()->close();
303  sockstr.rdbuf()->attach(socketd);
304  }
305  return socketd;
306 }
307 
308 }
virtual std::streamsize xsgetn(char_type *__s, std::streamsize __n)
socketbuf * rdbuf()
int accept(socketstream &sockstr)
virtual int_type underflow()
virtual int_type overflow(int_type c=traits_type::eof())
int attach(int sd)
int ssize_t
Definition: isockstream.cpp:25
virtual int sync()
virtual std::streamsize xsputn(const char_type *__s, std::streamsize __n)
int open(const char hostname[], int port)