tcp.cpp
1 /***************************************************************************
2  Copyright (C) 2002-2015 Kentaro Kitagawa
3  kitagawa@phys.s.u-tokyo.ac.jp
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  You should have received a copy of the GNU Library General
11  Public License and a list of authors along with this program;
12  see the files COPYING and AUTHORS.
13 ***************************************************************************/
14 #include "tcp.h"
15 
16 #ifdef TCP_SOCKET
17 
18 #if defined WINDOWS || defined __WIN32__ || defined _WIN32
19  #include <winsock2.h>
20  #include <ws2tcpip.h>
21 
22  static class WSockInit {
23  public:
24  WSockInit() {
25  int ret = WSAStartup(MAKEWORD(2,0), &data);
26  if(ret)
27  fprintf(stderr, "WSAStartup() has failed %d\n", ret);
28  }
29  ~WSockInit() {
30  int ret = WSACleanup();
31  if(ret)
32  fprintf(stderr, "WSACleanup() has failed %d\n", ret);
33  }
34  private:
35  WSADATA data;
36  } s_wsockinit;
37 
38 #else
39  #include <sys/types.h>
40  #include <sys/socket.h>
41  #include <netinet/in.h>
42  #include <netinet/tcp.h>
43  #include <arpa/inet.h>
44  #include <netdb.h>
45  #include <errno.h>
46  #include <unistd.h>
47 #endif
48 
49 #define MIN_BUFFER_SIZE 256
50 
51 XTCPSocketPort::XTCPSocketPort(XCharInterface *intf)
52  : XPort(intf), m_socket(-1) {
53 
54 }
55 XTCPSocketPort::~XTCPSocketPort() {
56  if(m_socket >= 0) {
57 #if defined WINDOWS || defined __WIN32__ || defined _WIN32
58  closesocket(m_socket);
59 #else
60  close(m_socket);
61 #endif
62  }
63 }
64 void
65 XTCPSocketPort::reopen_socket() throw (XInterface::XCommError &) {
66  if(m_socket >= 0) {
67 #if defined WINDOWS || defined __WIN32__ || defined _WIN32
68  closesocket(m_socket);
69 #else
70  close(m_socket);
71 #endif
72  }
73  open(0);
74 }
75 
76 void
77 XTCPSocketPort::open(const XCharInterface *pInterface) throw (XInterface::XCommError &) {
78  struct sockaddr_in dstaddr;
79 
80  std::string ipaddr = portString();
81  int colpos = ipaddr.find_first_of(':');
82  if(colpos == std::string::npos)
83  throw XInterface::XCommError(i18n("tcp socket creation failed"), __FILE__, __LINE__);
84  unsigned int port;
85  if(sscanf(ipaddr.substr(colpos + 1).c_str(), "%u", &port) != 1)
86  throw XInterface::XCommError(i18n("tcp socket creation failed"), __FILE__, __LINE__);
87  ipaddr = ipaddr.substr(0, colpos);
88 
89  m_socket = socket(AF_INET, SOCK_STREAM, 0);
90  if(m_socket < 0) {
91  throw XInterface::XCommError(i18n("tcp socket creation failed"), __FILE__, __LINE__);
92  }
93 
94  struct timeval timeout;
95  timeout.tv_sec = 3; //3sec. timeout.
96  timeout.tv_usec = 0;
97  if(setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) ||
98  setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout))){
99  throw XInterface::XCommError(i18n("tcp socket setting options failed"), __FILE__, __LINE__);
100  }
101 
102  int opt = 1;
103  if(setsockopt(m_socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&opt, sizeof(opt)))
104  throw XInterface::XCommError(i18n("tcp socket setting options failed"), __FILE__, __LINE__);
105 
106  //disables NAGLE protocol
107  opt = 1;
108  if(setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt)))
109  throw XInterface::XCommError(i18n("tcp socket setting options failed"), __FILE__, __LINE__);
110 // opt = 0;
111 // if(setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&opt, sizeof(opt)))
112 // throw XInterface::XCommError(i18n("tcp socket setting options failed"), __FILE__, __LINE__);
113 
114  memset( &dstaddr, 0, sizeof(dstaddr));
115  dstaddr.sin_port = htons(port);
116  dstaddr.sin_family = AF_INET;
117  dstaddr.sin_addr.s_addr = inet_addr(ipaddr.c_str());
118 
119  if(connect(m_socket, (struct sockaddr *) &dstaddr, sizeof(dstaddr)) == -1) {
120 #if defined WINDOWS || defined __WIN32__ || defined _WIN32
121  errno = WSAGetLastError();
122 #endif
123  throw XInterface::XCommError(formatString_tr(I18N_NOOP("tcp open failed %u"), errno).c_str(), __FILE__, __LINE__);
124  }
125 }
126 void
127 XTCPSocketPort::send(const char *str) throw (XInterface::XCommError &) {
128  XString buf(str);
129  buf += eos();
130  this->write(buf.c_str(), buf.length());
131 }
132 void
133 XTCPSocketPort::write(const char *sendbuf, int size) throw (XInterface::XCommError &) {
134  fd_set fs;
135  FD_ZERO(&fs);
136  FD_SET(m_socket , &fs);
137  struct timeval timeout;
138  timeout.tv_sec = 3; //3sec. timeout.
139  timeout.tv_usec = 0;
140  int ret = ::select(0, NULL, &fs, NULL, &timeout);
141  if(ret < 0)
142  throw XInterface::XCommError(i18n("tcp writing failed"), __FILE__, __LINE__);
143  if(ret == 0)
144  msecsleep(10);
145 
146  int wlen = 0;
147  do {
148  int ret = ::send(m_socket, sendbuf, size - wlen, 0);
149  if(ret <= 0) {
150 #if defined WINDOWS || defined __WIN32__ || defined _WIN32
151  errno = WSAGetLastError();
152 // if((errno == WSAEINTR)) {
153 #endif
154  if((errno == EINTR) || (errno == EAGAIN)) {
155  dbgPrint("TCP/IP, EINTR/EAGAIN, trying to continue.");
156  continue;
157  }
158  gErrPrint(i18n("write error, trying to reopen the socket"));
159  reopen_socket();
160  throw XInterface::XCommError(i18n("tcp writing failed"), __FILE__, __LINE__);
161  }
162  wlen += ret;
163  sendbuf += ret;
164  } while (wlen < size);
165 }
166 void
167 XTCPSocketPort::receive() throw (XInterface::XCommError &) {
168  fd_set fs;
169  FD_ZERO(&fs);
170  FD_SET(m_socket , &fs);
171  struct timeval timeout;
172  timeout.tv_sec = 3; //3sec. timeout.
173  timeout.tv_usec = 0;
174  int ret = ::select(0, &fs, NULL, NULL, &timeout);
175  if(ret < 0)
176  throw XInterface::XCommError(i18n("tcp reading failed"), __FILE__, __LINE__);
177  if(ret == 0)
178  msecsleep(10);
179 
180  buffer().resize(MIN_BUFFER_SIZE);
181 
182  const char *ceos = eos().c_str();
183  unsigned int eos_len = eos().length();
184  unsigned int len = 0;
185  for(;;) {
186  if(buffer().size() <= len + 1)
187  buffer().resize(len + MIN_BUFFER_SIZE);
188  int rlen = ::recv(m_socket, &buffer().at(len), 1, 0);
189  if(rlen == 0) {
190  buffer().at(len) = '\0';
191  throw XInterface::XCommError(i18n("read time-out, buf=;") + &buffer().at(0), __FILE__, __LINE__);
192  }
193  if(rlen < 0) {
194 #if defined WINDOWS || defined __WIN32__ || defined _WIN32
195  errno = WSAGetLastError();
196 // if((errno == WSAEINTR)) {
197 #endif
198  if((errno == EINTR) || (errno == EAGAIN)) {
199  dbgPrint("TCP/IP, EINTR/EAGAIN, trying to continue.");
200  continue;
201  }
202  gErrPrint(formatString_tr(I18N_NOOP("read error %u, trying to reopen the socket"), errno).c_str());
203  reopen_socket();
204  throw XInterface::XCommError(i18n("tcp reading failed"), __FILE__, __LINE__);
205  }
206  len += rlen;
207  if(len >= eos_len) {
208  if( !strncmp(&buffer().at(len - eos_len), ceos, eos_len)) {
209  break;
210  }
211  }
212  }
213 
214  buffer().resize(len + 1);
215  buffer().at(len) = '\0';
216 }
217 void
218 XTCPSocketPort::receive(unsigned int length) throw (XInterface::XCommError &) {
219  buffer().resize(length);
220  unsigned int len = 0;
221 
222  while(len < length) {
223  int rlen = ::recv(m_socket, &buffer().at(len), 1, 0);
224  if(rlen == 0)
225  throw XInterface::XCommError(i18n("read time-out"), __FILE__, __LINE__);
226  if(rlen < 0) {
227 #if defined WINDOWS || defined __WIN32__ || defined _WIN32
228  errno = WSAGetLastError();
229  if((errno == WSAEINTR)) {
230 #else
231  if((errno == EINTR) || (errno == EAGAIN)) {
232 #endif
233  dbgPrint("TCP/IP, EINTR/EAGAIN, trying to continue.");
234  continue;
235  }
236  gErrPrint(i18n("read error, trying to reopen the socket"));
237  reopen_socket();
238  throw XInterface::XCommError(i18n("tcp reading failed"), __FILE__, __LINE__);
239  }
240  len += rlen;
241  }
242 }
243 
244 #endif //TCP_POSIX
245 

Generated for KAME4 by  doxygen 1.8.3