urg_tcpclient.c
Go to the documentation of this file.
1 
10 // http://www.ne.jp/asahi/hishidama/home/tech/lang/socket.html
11 
12 #include "urg_c/urg_detect_os.h"
13 #include <string.h>
14 #if defined(URG_WINDOWS_OS)
15 #else
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #endif
20 #include "urg_c/urg_tcpclient.h"
21 
22 #include <stdio.h>
23 
24 enum {
26 };
27 
28 
30 {
31  ring_initialize(&cli->rb, cli->buf, RB_BITSHIFT);
32 }
33 
34 
35 // get number of data in buffer.
37 {
38  return ring_size(&cli->rb);
39 }
40 
41 
43  const char* data, int size)
44 {
45  return ring_write(&cli->rb, data, size);
46 }
47 
48 
49 static int tcpclient_buffer_read(urg_tcpclient_t* cli, char* data, int size)
50 {
51  return ring_read(&cli->rb, data, size);
52 }
53 
54 
56 {
57 #if defined(URG_WINDOWS_OS)
58  u_long flag = 0;
59  ioctlsocket(cli->sock_desc, FIONBIO, &flag);
60 #else
61  int flag = 0;
62  fcntl(cli->sock_desc, F_SETFL, flag);
63 #endif
64 }
65 
66 
67 int tcpclient_open(urg_tcpclient_t* cli, const char* ip_str, int port_num)
68 {
69  enum { Connect_timeout_second = 2 };
70  fd_set rmask, wmask;
71  struct timeval tv = { Connect_timeout_second, 0 };
72 #if defined(URG_WINDOWS_OS)
73  u_long flag;
74 #else
75  int flag;
76  int sock_optval = -1;
77  int sock_optval_size = sizeof(sock_optval);
78 #endif
79  int ret;
80 
81  cli->sock_desc = Invalid_desc;
82  cli->pushed_back = -1; // no pushed back char.
83 
84 #if defined(URG_WINDOWS_OS)
85  {
86  static int is_initialized = 0;
87  WORD wVersionRequested = 0x0202;
88  WSADATA WSAData;
89  int err;
90  if (!is_initialized) {
91  err = WSAStartup(wVersionRequested, &WSAData);
92  if (err != 0) {
93  return -1;
94  }
95  is_initialized = 1;
96  }
97  }
98 #endif
99 
101 
102  cli->sock_addr_size = sizeof (struct sockaddr_in);
103  if ((cli->sock_desc = (int)socket(AF_INET, SOCK_STREAM, 0)) < 0) {
104  return -1;
105  }
106 
107  memset((char*)&(cli->server_addr), 0, sizeof(cli->sock_addr_size));
108  cli->server_addr.sin_family = AF_INET;
109  cli->server_addr.sin_port = htons(port_num);
110 
111  if (!strcmp(ip_str, "localhost")) {
112  ip_str = "127.0.0.1";
113  }
114 
115  /* bind is not required, and port number is dynamic */
116  if ((cli->server_addr.sin_addr.s_addr = inet_addr(ip_str)) == INADDR_NONE) {
117  return -1;
118  }
119 
120 #if defined(URG_WINDOWS_OS)
121  //ノンブロックに変更
122  flag = 1;
123  ioctlsocket(cli->sock_desc, FIONBIO, &flag);
124 
125  if (connect(cli->sock_desc, (const struct sockaddr *)&(cli->server_addr),
126  cli->sock_addr_size) == SOCKET_ERROR) {
127  int error_number = WSAGetLastError();
128  if (error_number != WSAEWOULDBLOCK) {
129  tcpclient_close(cli);
130  return -1;
131  }
132 
133  FD_ZERO(&rmask);
134  FD_SET((SOCKET)cli->sock_desc, &rmask);
135  wmask = rmask;
136 
137  ret = select((int)cli->sock_desc + 1, &rmask, &wmask, NULL, &tv);
138  if (ret == 0) {
139  // タイムアウト
140  tcpclient_close(cli);
141  return -2;
142  }
143  }
144  //ブロックモードにする set_block_mode(cli); #else //ノンブロックに変更 flag = fcntl(cli->sock_desc, F_GETFL, 0); fcntl(cli->sock_desc, F_SETFL, flag | O_NONBLOCK); if (connect(cli->sock_desc, (const struct sockaddr *)&(cli->server_addr), cli->sock_addr_size) < 0) { if (errno != EINPROGRESS) { tcpclient_close(cli); return -1; } // EINPROGRESS:コネクション要求は始まったが、まだ完了していない FD_ZERO(&rmask); FD_SET(cli->sock_desc, &rmask); wmask = rmask; ret = select(cli->sock_desc + 1, &rmask, &wmask, NULL, &tv); if (ret <= 0) { // タイムアウト処理 tcpclient_close(cli); return -2; } if (getsockopt(cli->sock_desc, SOL_SOCKET, SO_ERROR, (int*)&sock_optval, (socklen_t*)&sock_optval_size) != 0) { // 接続に失敗 tcpclient_close(cli); return -3; } if (sock_optval != 0) { // 接続に失敗 tcpclient_close(cli); return -4; } set_block_mode(cli); } #endif return 0; } void tcpclient_close(urg_tcpclient_t* cli) { if (cli->sock_desc != Invalid_desc) { #if defined(URG_WINDOWS_OS) closesocket(cli->sock_desc); //WSACleanup(); #else close(cli->sock_desc); #endif cli->sock_desc = Invalid_desc; } } int tcpclient_read(urg_tcpclient_t* cli, char* userbuf, int req_size, int timeout) { // number of data in buffer. int num_in_buf = tcpclient_buffer_data_num(cli); int sock = cli->sock_desc; int rem_size = req_size; // remaining size to be sent back. int n; // copy data in buffer to user buffer and return with requested size. if (num_in_buf > 0) { n = tcpclient_buffer_read(cli, userbuf, req_size); rem_size = req_size - n; // lacking size. if (rem_size <= 0) { return req_size; } num_in_buf = tcpclient_buffer_data_num(cli); } // data in buffer was not enough, read from socket to fill buffer, // without blocking, i.e. read from system's buffer. { char tmpbuf[BUFSIZE]; // receive with non-blocking mode. #if defined(URG_WINDOWS_OS) int no_timeout = 1; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&no_timeout, sizeof(struct timeval)); n = recv(sock, tmpbuf, BUFSIZE - num_in_buf, 0); #else n = recv(sock, tmpbuf, BUFSIZE - num_in_buf, MSG_DONTWAIT); #endif if (n > 0) { tcpclient_buffer_write(cli, tmpbuf, n); // copy socket to my buffer } n = tcpclient_buffer_read(cli, &userbuf[req_size-rem_size], rem_size); // n never be greater than rem_size rem_size -= n; if (rem_size <= 0) { return req_size; } } // lastly recv with blocking but with time out to read necessary size. { #if defined(URG_WINDOWS_OS) setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(struct timeval)); #else struct timeval tv; tv.tv_sec = timeout / 1000; // millisecond to seccond tv.tv_usec = (timeout % 1000) * 1000; // millisecond to microsecond setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); #endif //4th arg 0:no flag n = recv(sock, &userbuf[req_size-rem_size], rem_size, 0); // n never be greater than rem_size if (n > 0) { rem_size -= n; } } return (req_size - rem_size); // last return may be less than req_size; } int tcpclient_write(urg_tcpclient_t* cli, const char* buf, int size) { // blocking if data size is larger than system's buffer. return send(cli->sock_desc, buf, size, 0); //4th arg 0: no flag } int tcpclient_error(urg_tcpclient_t* cli, char* error_message, int max_size) { (void)cli; (void)error_message; (void)max_size; // not implemented yet. return -1; } int tcpclient_readline(urg_tcpclient_t* cli, char* userbuf, int buf_size, int timeout) { int n = 0; int i = 0; if (cli->pushed_back > 0) { userbuf[i] = cli->pushed_back; i++; cli->pushed_back = -1; } for (; i < buf_size; ++i) { char ch; n = tcpclient_read(cli, &ch, 1, timeout); if (n <= 0) { break; // error } if (ch == '\n' || ch == '\r') { break; // success } userbuf[i] = ch; } if (i >= buf_size) { // No CR or LF found. --i; cli->pushed_back = userbuf[buf_size - 1] & 0xff; userbuf[buf_size - 1] = '\0'; } userbuf[i] = '\0'; if (i == 0 && n <= 0) { // error return -1; } return i; // the number of characters filled into user buffer. }
145  set_block_mode(cli);
146 
147 #else
148  //ノンブロックに変更
149  flag = fcntl(cli->sock_desc, F_GETFL, 0);
150  fcntl(cli->sock_desc, F_SETFL, flag | O_NONBLOCK);
151 
152  if (connect(cli->sock_desc, (const struct sockaddr *)&(cli->server_addr),
153  cli->sock_addr_size) < 0) {
154  if (errno != EINPROGRESS) {
155  tcpclient_close(cli);
156  return -1;
157  }
158 
159  // EINPROGRESS:コネクション要求は始まったが、まだ完了していない
160  FD_ZERO(&rmask);
161  FD_SET(cli->sock_desc, &rmask);
162  wmask = rmask;
163 
164  ret = select(cli->sock_desc + 1, &rmask, &wmask, NULL, &tv);
165  if (ret <= 0) {
166  // タイムアウト処理
167  tcpclient_close(cli);
168  return -2;
169  }
170 
171  if (getsockopt(cli->sock_desc, SOL_SOCKET, SO_ERROR, (int*)&sock_optval,
172  (socklen_t*)&sock_optval_size) != 0) {
173  // 接続に失敗
174  tcpclient_close(cli);
175  return -3;
176  }
177 
178  if (sock_optval != 0) {
179  // 接続に失敗
180  tcpclient_close(cli);
181  return -4;
182  }
183 
184  set_block_mode(cli);
185  }
186 #endif
187 
188  return 0;
189 }
190 
191 
193 {
194  if (cli->sock_desc != Invalid_desc) {
195 #if defined(URG_WINDOWS_OS)
196  closesocket(cli->sock_desc);
197  //WSACleanup();
198 #else
199  close(cli->sock_desc);
200 #endif
201  cli->sock_desc = Invalid_desc;
202  }
203 }
204 
205 
207  char* userbuf, int req_size, int timeout)
208 {
209  // number of data in buffer.
210  int num_in_buf = tcpclient_buffer_data_num(cli);
211  int sock = cli->sock_desc;
212  int rem_size = req_size; // remaining size to be sent back.
213  int n;
214 
215  // copy data in buffer to user buffer and return with requested size.
216  if (num_in_buf > 0) {
217  n = tcpclient_buffer_read(cli, userbuf, req_size);
218  rem_size = req_size - n; // lacking size.
219  if (rem_size <= 0) {
220  return req_size;
221  }
222 
223  num_in_buf = tcpclient_buffer_data_num(cli);
224  }
225 
226  // data in buffer was not enough, read from socket to fill buffer,
227  // without blocking, i.e. read from system's buffer.
228  {
229  char tmpbuf[BUFSIZE];
230  // receive with non-blocking mode.
231 #if defined(URG_WINDOWS_OS)
232  int no_timeout = 1;
233  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&no_timeout, sizeof(struct timeval));
234  n = recv(sock, tmpbuf, BUFSIZE - num_in_buf, 0);
235 #else
236  n = recv(sock, tmpbuf, BUFSIZE - num_in_buf, MSG_DONTWAIT);
237 #endif
238  if (n > 0) {
239  tcpclient_buffer_write(cli, tmpbuf, n); // copy socket to my buffer
240  }
241 
242  n = tcpclient_buffer_read(cli, &userbuf[req_size-rem_size], rem_size);
243  // n never be greater than rem_size
244  rem_size -= n;
245  if (rem_size <= 0) {
246  return req_size;
247  }
248  }
249 
250  // lastly recv with blocking but with time out to read necessary size.
251  {
252 #if defined(URG_WINDOWS_OS)
253  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
254  (const char *)&timeout, sizeof(struct timeval));
255 #else
256  struct timeval tv;
257  tv.tv_sec = timeout / 1000; // millisecond to seccond
258  tv.tv_usec = (timeout % 1000) * 1000; // millisecond to microsecond
259  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
260 #endif
261  //4th arg 0:no flag
262  n = recv(sock, &userbuf[req_size-rem_size], rem_size, 0);
263  // n never be greater than rem_size
264  if (n > 0) {
265  rem_size -= n;
266  }
267  }
268 
269  return (req_size - rem_size); // last return may be less than req_size;
270 }
271 
272 
273 int tcpclient_write(urg_tcpclient_t* cli, const char* buf, int size)
274 {
275  // blocking if data size is larger than system's buffer.
276  return send(cli->sock_desc, buf, size, 0); //4th arg 0: no flag
277 }
278 
279 
280 int tcpclient_error(urg_tcpclient_t* cli, char* error_message, int max_size)
281 {
282  (void)cli;
283  (void)error_message;
284  (void)max_size;
285 
286  // not implemented yet.
287 
288  return -1;
289 }
290 
291 
293  char* userbuf, int buf_size, int timeout)
294 {
295  int n = 0;
296  int i = 0;
297 
298  if (cli->pushed_back > 0) {
299  userbuf[i] = cli->pushed_back;
300  i++;
301  cli->pushed_back = -1;
302  }
303  for (; i < buf_size; ++i) {
304  char ch;
305  n = tcpclient_read(cli, &ch, 1, timeout);
306  if (n <= 0) {
307  break; // error
308  }
309  if (ch == '\n' || ch == '\r') {
310  break; // success
311  }
312  userbuf[i] = ch;
313  }
314 
315  if (i >= buf_size) { // No CR or LF found.
316  --i;
317  cli->pushed_back = userbuf[buf_size - 1] & 0xff;
318  userbuf[buf_size - 1] = '\0';
319  }
320  userbuf[i] = '\0';
321 
322  if (i == 0 && n <= 0) { // error
323  return -1;
324  }
325 
326  return i; // the number of characters filled into user buffer.
327 }
Invalid_desc
@ Invalid_desc
Definition: urg_tcpclient.c:25
ring_read
int ring_read(ring_buffer_t *ring, char *buffer, int size)
データの取り出し
Definition: urg_ring_buffer.c:83
urg_tcpclient_t::buf
char buf[RB_SIZE]
Definition: urg_tcpclient.h:52
tcpclient_buffer_data_num
static int tcpclient_buffer_data_num(urg_tcpclient_t *cli)
Definition: urg_tcpclient.c:36
tcpclient_read
int tcpclient_read(urg_tcpclient_t *cli, char *userbuf, int req_size, int timeout)
read from socket.
Definition: urg_tcpclient.c:206
urg_tcpclient_t::rb
ring_buffer_t rb
Definition: urg_tcpclient.h:51
urg_tcpclient_t::sock_addr_size
int sock_addr_size
Definition: urg_tcpclient.h:48
tcpclient_readline
int tcpclient_readline(urg_tcpclient_t *cli, char *userbuf, int buf_size, int timeout)
read one line from socket.
Definition: urg_tcpclient.c:292
urg_tcpclient_t
TCP/IP connection.
Definition: urg_tcpclient.h:44
ring_initialize
void ring_initialize(ring_buffer_t *ring, char *buffer, const int shift_length)
初期化
Definition: urg_ring_buffer.c:13
tcpclient_close
void tcpclient_close(urg_tcpclient_t *cli)
destructor of tcp client module
Definition: urg_tcpclient.c:192
urg_tcpclient.h
TCP/IP read/write functions.
BUFSIZE
@ BUFSIZE
Definition: urg_tcpclient.h:39
tcpclient_buffer_write
static int tcpclient_buffer_write(urg_tcpclient_t *cli, const char *data, int size)
Definition: urg_tcpclient.c:42
urg_tcpclient_t::pushed_back
int pushed_back
Definition: urg_tcpclient.h:55
urg_detect_os.h
OS の検出.
tcpclient_buffer_read
static int tcpclient_buffer_read(urg_tcpclient_t *cli, char *data, int size)
Definition: urg_tcpclient.c:49
urg_tcpclient_t::sock_desc
int sock_desc
Definition: urg_tcpclient.h:47
set_block_mode
static void set_block_mode(urg_tcpclient_t *cli)
Definition: urg_tcpclient.c:55
tcpclient_error
int tcpclient_error(urg_tcpclient_t *cli, char *error_message, int max_size)
Definition: urg_tcpclient.c:280
ring_write
int ring_write(ring_buffer_t *ring, const char *data, int size)
データの格納
Definition: urg_ring_buffer.c:52
RB_BITSHIFT
@ RB_BITSHIFT
Definition: urg_tcpclient.h:34
urg_tcpclient_t::server_addr
struct sockaddr_in server_addr
Definition: urg_tcpclient.h:46
tcpclient_write
int tcpclient_write(urg_tcpclient_t *cli, const char *buf, int size)
write to socket.
Definition: urg_tcpclient.c:273
tcpclient_open
int tcpclient_open(urg_tcpclient_t *cli, const char *ip_str, int port_num)
constructor of tcp client module
Definition: urg_tcpclient.c:67
tcpclient_buffer_init
static void tcpclient_buffer_init(urg_tcpclient_t *cli)
Definition: urg_tcpclient.c:29
ring_size
int ring_size(const ring_buffer_t *ring)
格納データ数を返す
Definition: urg_ring_buffer.c:28


urg_c
Author(s): Satofumi Kamimura , Katsumi Kimoto, Adrian Boeing
autogenerated on Wed Mar 2 2022 01:08:11