MFEM v2.0
|
00001 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at 00002 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights 00003 // reserved. See file COPYRIGHT for details. 00004 // 00005 // This file is part of the MFEM library. For more information and source code 00006 // availability see http://mfem.googlecode.com. 00007 // 00008 // MFEM is free software; you can redistribute it and/or modify it under the 00009 // terms of the GNU Lesser General Public License (as published by the Free 00010 // Software Foundation) version 2.1 dated February 1999. 00011 00012 #include "socketstream.hpp" 00013 00014 #include <cstring> // memset, memcpy 00015 #include <netdb.h> // gethostbyname 00016 #include <arpa/inet.h> // htons 00017 #include <sys/types.h> // socket, setsockopt, connect, recv, send 00018 #include <sys/socket.h> // socket, setsockopt, connect, recv, send 00019 #include <unistd.h> // close 00020 00021 int socketbuf::attach(int sd) 00022 { 00023 int old_sd = socket_descriptor; 00024 pubsync(); 00025 socket_descriptor = sd; 00026 setg(NULL, NULL, NULL); 00027 setp(obuf, obuf + buflen); 00028 return old_sd; 00029 } 00030 00031 int socketbuf::open(const char hostname[], int port) 00032 { 00033 struct sockaddr_in sa; 00034 struct hostent *hp; 00035 00036 close(); 00037 setg(NULL, NULL, NULL); 00038 setp(obuf, obuf + buflen); 00039 00040 hp = gethostbyname(hostname); 00041 if (hp == NULL) 00042 { 00043 socket_descriptor = -3; 00044 return -1; 00045 } 00046 memset(&sa, 0, sizeof(sa)); 00047 memcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length); 00048 sa.sin_family = hp->h_addrtype; 00049 sa.sin_port = htons(port); 00050 socket_descriptor = socket(hp->h_addrtype, SOCK_STREAM, 0); 00051 if (socket_descriptor < 0) 00052 return -1; 00053 if (connect(socket_descriptor, 00054 (const struct sockaddr *)&sa, sizeof(sa)) < 0) 00055 { 00056 ::close(socket_descriptor); 00057 socket_descriptor = -2; 00058 return -1; 00059 } 00060 return 0; 00061 } 00062 00063 int socketbuf::close() 00064 { 00065 if (is_open()) 00066 { 00067 pubsync(); 00068 int err = ::close(socket_descriptor); 00069 socket_descriptor = -1; 00070 return err; 00071 } 00072 return 0; 00073 } 00074 00075 int socketbuf::sync() 00076 { 00077 ssize_t bw, n = pptr() - pbase(); 00078 // std::cout << "[socketbuf::sync n=" << n << ']' << std::endl; 00079 while (n > 0) 00080 { 00081 #ifdef MSG_NOSIGNAL 00082 bw = send(socket_descriptor, pptr() - n, n, MSG_NOSIGNAL); 00083 #else 00084 bw = send(socket_descriptor, pptr() - n, n, 0); 00085 #endif 00086 if (bw < 0) 00087 { 00088 setp(pptr() - n, obuf + buflen); 00089 pbump(n); 00090 return -1; 00091 } 00092 n -= bw; 00093 } 00094 setp(obuf, obuf + buflen); 00095 return 0; 00096 } 00097 00098 socketbuf::int_type socketbuf::underflow() 00099 { 00100 // assuming (gptr() < egptr()) is false 00101 ssize_t br = recv(socket_descriptor, ibuf, buflen, 0); 00102 // std::cout << "[socketbuf::underflow br=" << br << ']' 00103 // << std::endl; 00104 if (br <= 0) 00105 { 00106 setg(NULL, NULL, NULL); 00107 return traits_type::eof(); 00108 } 00109 setg(ibuf, ibuf, ibuf + br); 00110 return traits_type::to_int_type(*ibuf); 00111 } 00112 00113 socketbuf::int_type socketbuf::overflow(int_type c) 00114 { 00115 if (sync() < 0) 00116 return traits_type::eof(); 00117 if (traits_type::eq_int_type(c, traits_type::eof())) 00118 return traits_type::not_eof(c); 00119 *pptr() = traits_type::to_char_type(c); 00120 pbump(1); 00121 return c; 00122 } 00123 00124 std::streamsize socketbuf::xsgetn(char_type *__s, std::streamsize __n) 00125 { 00126 // std::cout << "[socketbuf::xsgetn __n=" << __n << ']' 00127 // << std::endl; 00128 const std::streamsize bn = egptr() - gptr(); 00129 if (__n <= bn) 00130 { 00131 traits_type::copy(__s, gptr(), __n); 00132 gbump(__n); 00133 return __n; 00134 } 00135 traits_type::copy(__s, gptr(), bn); 00136 setg(NULL, NULL, NULL); 00137 std::streamsize remain = __n - bn; 00138 char_type *end = __s + __n; 00139 ssize_t br; 00140 while (remain > 0) 00141 { 00142 br = recv(socket_descriptor, end - remain, remain, 0); 00143 if (br <= 0) 00144 return (__n - remain); 00145 remain -= br; 00146 } 00147 return __n; 00148 } 00149 00150 std::streamsize socketbuf::xsputn(const char_type *__s, std::streamsize __n) 00151 { 00152 // std::cout << "[socketbuf::xsputn __n=" << __n << ']' 00153 // << std::endl; 00154 if (pptr() + __n <= epptr()) 00155 { 00156 traits_type::copy(pptr(), __s, __n); 00157 pbump(__n); 00158 return __n; 00159 } 00160 if (sync() < 0) 00161 return 0; 00162 ssize_t bw; 00163 std::streamsize remain = __n; 00164 const char_type *end = __s + __n; 00165 while (remain > buflen) 00166 { 00167 #ifdef MSG_NOSIGNAL 00168 bw = send(socket_descriptor, end - remain, remain, MSG_NOSIGNAL); 00169 #else 00170 bw = send(socket_descriptor, end - remain, remain, 0); 00171 #endif 00172 if (bw < 0) 00173 return (__n - remain); 00174 remain -= bw; 00175 } 00176 if (remain > 0) 00177 { 00178 traits_type::copy(pptr(), end - remain, remain); 00179 pbump(remain); 00180 } 00181 return __n; 00182 } 00183 00184 00185 socketserver::socketserver(int port) 00186 { 00187 listen_socket = socket(PF_INET, SOCK_STREAM, 0); // tcp socket 00188 if (listen_socket < 0) 00189 { 00190 return; 00191 } 00192 int on = 1; 00193 if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, 00194 &on, sizeof(on)) < 0) 00195 { 00196 ::close(listen_socket); 00197 listen_socket = -2; 00198 return; 00199 } 00200 struct sockaddr_in sa; 00201 memset(&sa, 0, sizeof(sa)); 00202 sa.sin_family = AF_INET; 00203 sa.sin_port = htons(port); 00204 sa.sin_addr.s_addr = INADDR_ANY; 00205 if (bind(listen_socket, (const struct sockaddr *)&sa, sizeof(sa))) 00206 { 00207 ::close(listen_socket); 00208 listen_socket = -3; 00209 return; 00210 } 00211 const int backlog = 4; 00212 if (listen(listen_socket, backlog) < 0) 00213 { 00214 ::close(listen_socket); 00215 listen_socket = -4; 00216 return; 00217 } 00218 } 00219 00220 int socketserver::close() 00221 { 00222 if (!good()) 00223 return 0; 00224 int err = ::close(listen_socket); 00225 listen_socket = -1; 00226 return err; 00227 } 00228 00229 int socketserver::accept(socketstream &sockstr) 00230 { 00231 if (!good()) 00232 return -1; 00233 int socketd = ::accept(listen_socket, NULL, NULL); 00234 if (socketd >= 0) 00235 { 00236 sockstr.rdbuf()->close(); 00237 sockstr.rdbuf()->attach(socketd); 00238 } 00239 return socketd; 00240 }