1 // Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "isockstream.hpp"
13 #include "globals.hpp"
14 #include <iostream>
15 #include <cstring>
16 #include <cstdlib>
17 #include <errno.h>
18 #ifndef _WIN32
19 #include <netinet/in.h>
20 #include <netdb.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <unistd.h>
24 #else
25 #include <winsock.h>
26 typedef int ssize_t;
27 typedef int socklen_t;
28 #define close closesocket
29 // Link with ws2_32.lib
30 #pragma comment(lib, "ws2_32.lib")
31 #endif
32 
33 using namespace std;
34 
35 namespace mfem
36 {
37 
isockstream(int port)38 isockstream::isockstream(int port)
39 {
40    portnum = port;
41 
42    if ( (portID = establish()) < 0)
43       mfem::out << "Server couldn't be established on port "
44                 << portnum << endl;
45    Buf = NULL;
46 }
47 
establish()48 int isockstream::establish()
49 {
50    // char myname[129];
51    char   myname[] = "localhost";
52    int    port;
53    struct sockaddr_in sa;
54    struct hostent *hp;
55 
56    memset(&sa, 0, sizeof(struct sockaddr_in));
57    // gethostname(myname, 128);
58    hp= gethostbyname(myname);
59 
60    if (hp == NULL)
61    {
62       mfem::err << "isockstream::establish(): gethostbyname() failed!\n"
63                 << "isockstream::establish(): gethostname() returned: '"
64                 << myname << "'" << endl;
65       error = 1;
66       return (-1);
67    }
68 
69    sa.sin_family= hp->h_addrtype;
70    sa.sin_port= htons(portnum);
71 
72    if ((port = socket(AF_INET, SOCK_STREAM, 0)) < 0)
73    {
74       mfem::err << "isockstream::establish(): socket() failed!" << endl;
75       error = 2;
76       return (-1);
77    }
78 
79    int on=1;
80    setsockopt(port, SOL_SOCKET, SO_REUSEADDR, (char *)(&on), sizeof(on));
81 
82    if (bind(port,(const sockaddr*)&sa,(socklen_t)sizeof(struct sockaddr_in)) < 0)
83    {
84       mfem::err << "isockstream::establish(): bind() failed!" << endl;
85       close(port);
86       error = 3;
87       return (-1);
88    }
89 
90    listen(port, 4);
91    error = 0;
92    return (port);
93 }
94 
read_data(int s,char * buf,int n)95 int isockstream::read_data(int s, char *buf, int n)
96 {
97    int bcount;                      // counts bytes read
98    int br;                          // bytes read this pass
99 
100    bcount= 0;
101    while (bcount < n)               // loop until full buffer
102    {
103       if ((br = recv(s, buf, n - bcount, 0)) > 0)
104       {
105          bcount += br;                // increment byte counter
106          buf += br;                   // move buffer ptr for next read
107       }
108       else if (br < 0)               // signal an error to the caller
109       {
110          error = 4;
111          return (-1);
112       }
113    }
114    return (bcount);
115 }
116 
receive(std::istringstream ** in)117 void isockstream::receive(std::istringstream **in)
118 {
119    int size;
120    char length[32];
121 
122    if ((*in) != NULL)
123    {
124       delete (*in), *in = NULL;
125    }
126 
127    if (portID == -1)
128    {
129       return;
130    }
131 
132    if ((socketID = accept(portID, NULL, NULL)) < 0)
133    {
134       mfem::out << "Server failed to accept connection." << endl;
135       error = 5;
136       return;
137    }
138 
139    if (recv(socketID, length, 32, 0) < 0)
140    {
141       error = 6;
142       return;
143    }
144    size = atoi(length);
145 
146    if (Buf != NULL)
147    {
148       delete [] Buf;
149    }
150    Buf = new char[size+1];
151    if (size != read_data(socketID, Buf, size))
152    {
153       mfem::out << "Not all the data has been read" << endl;
154    }
155 #ifdef DEBUG
156    else
157    {
158       mfem::out << "Reading " << size << " bytes is successful" << endl;
159    }
160 #endif
161    Buf[size] = '\0';
162 
163    close(socketID);
164    (*in) = new istringstream(Buf);
165 }
166 
~isockstream()167 isockstream::~isockstream()
168 {
169    if (Buf != NULL)
170    {
171       delete [] Buf;
172    }
173    if (portID != -1)
174    {
175       close(portID);
176    }
177 }
178 
179 }
180