urg_tcpclient.c
Go to the documentation of this file.
00001 
00010 // http://www.ne.jp/asahi/hishidama/home/tech/lang/socket.html
00011 
00012 #include "urg_c/urg_detect_os.h"
00013 #include <string.h>
00014 #if defined(URG_WINDOWS_OS)
00015 #else
00016 #include <unistd.h>
00017 #include <fcntl.h>
00018 #include <errno.h>
00019 #endif
00020 #include "urg_c/urg_tcpclient.h"
00021 
00022 #include <stdio.h>
00023 
00024 enum {
00025     Invalid_desc = -1,
00026 };
00027 
00028 
00029 static void tcpclient_buffer_init(urg_tcpclient_t* cli)
00030 {
00031     ring_initialize(&cli->rb, cli->buf, RB_BITSHIFT);
00032 }
00033 
00034 
00035 // get number of data in buffer.
00036 static int tcpclient_buffer_data_num(urg_tcpclient_t* cli)
00037 {
00038     return ring_size(&cli->rb);
00039 }
00040 
00041 
00042 static int tcpclient_buffer_write(urg_tcpclient_t* cli,
00043                                   const char* data, int size)
00044 {
00045     return ring_write(&cli->rb, data, size);
00046 }
00047 
00048 
00049 static int tcpclient_buffer_read(urg_tcpclient_t* cli, char* data, int size)
00050 {
00051     return ring_read(&cli->rb, data, size);
00052 }
00053 
00054 
00055 static void set_block_mode(urg_tcpclient_t* cli)
00056 {
00057 #if defined(URG_WINDOWS_OS)
00058     u_long flag = 0;
00059     ioctlsocket(cli->sock_desc, FIONBIO, &flag);
00060 #else
00061     int flag = 0;
00062     fcntl(cli->sock_desc, F_SETFL, flag);
00063 #endif
00064 }
00065 
00066 
00067 int tcpclient_open(urg_tcpclient_t* cli, const char* ip_str, int port_num)
00068 {
00069     enum { Connect_timeout_second = 2 };
00070     fd_set rmask, wmask;
00071     struct timeval tv = { Connect_timeout_second, 0 };
00072 #if defined(URG_WINDOWS_OS)
00073     u_long flag;
00074 #else
00075     int flag;
00076     int sock_optval = -1;
00077     int sock_optval_size = sizeof(sock_optval);
00078 #endif
00079     int ret;
00080 
00081     cli->sock_desc = Invalid_desc;
00082     cli->pushed_back = -1; // no pushed back char.
00083 
00084 #if defined(URG_WINDOWS_OS)
00085     {
00086         static int is_initialized = 0;
00087         WORD wVersionRequested = 0x0202;
00088         WSADATA WSAData;
00089         int err;
00090         if (!is_initialized) {
00091             err = WSAStartup(wVersionRequested, &WSAData);
00092             if (err != 0) {
00093                 return -1;
00094             }
00095             is_initialized = 1;
00096         }
00097     }
00098 #endif
00099 
00100     tcpclient_buffer_init(cli);
00101 
00102     cli->sock_addr_size = sizeof (struct sockaddr_in);
00103     if ((cli->sock_desc = (int)socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00104         return -1;
00105     }
00106 
00107     memset((char*)&(cli->server_addr), 0, sizeof(cli->sock_addr_size));
00108     cli->server_addr.sin_family = AF_INET;
00109     cli->server_addr.sin_port = htons(port_num);
00110 
00111     if (!strcmp(ip_str, "localhost")) {
00112         ip_str = "127.0.0.1";
00113     }
00114 
00115     /* bind is not required, and port number is dynamic */
00116     if ((cli->server_addr.sin_addr.s_addr = inet_addr(ip_str)) == INADDR_NONE) {
00117         return -1;
00118     }
00119 
00120 #if defined(URG_WINDOWS_OS)
00121     //ノンブロックに変更
00122     flag = 1;
00123     ioctlsocket(cli->sock_desc, FIONBIO, &flag);
00124 
00125     if (connect(cli->sock_desc, (const struct sockaddr *)&(cli->server_addr),
00126                 cli->sock_addr_size) == SOCKET_ERROR) {
00127         int error_number = WSAGetLastError();
00128         if (error_number != WSAEWOULDBLOCK) {
00129             tcpclient_close(cli);
00130             return -1;
00131         }
00132 
00133         FD_ZERO(&rmask);
00134         FD_SET((SOCKET)cli->sock_desc, &rmask);
00135         wmask = rmask;
00136 
00137         ret = select((int)cli->sock_desc + 1, &rmask, &wmask, NULL, &tv);
00138         if (ret == 0) {
00139             // タイムアウト
00140             tcpclient_close(cli);
00141             return -2;
00142         }
00143     }
00144     //ブロックモードにする
00145     set_block_mode(cli);
00146 
00147 #else
00148     //ノンブロックに変更
00149     flag = fcntl(cli->sock_desc, F_GETFL, 0);
00150     fcntl(cli->sock_desc, F_SETFL, flag | O_NONBLOCK);
00151 
00152     if (connect(cli->sock_desc, (const struct sockaddr *)&(cli->server_addr),
00153                 cli->sock_addr_size) < 0) {
00154         if (errno != EINPROGRESS) {
00155             tcpclient_close(cli);
00156             return -1;
00157         }
00158 
00159         // EINPROGRESS:コネクション要求は始まったが、まだ完了していない
00160         FD_ZERO(&rmask);
00161         FD_SET(cli->sock_desc, &rmask);
00162         wmask = rmask;
00163 
00164         ret = select(cli->sock_desc + 1, &rmask, &wmask, NULL, &tv);
00165         if (ret <= 0) {
00166             // タイムアウト処理
00167             tcpclient_close(cli);
00168             return -2;
00169         }
00170 
00171         if (getsockopt(cli->sock_desc, SOL_SOCKET, SO_ERROR, (int*)&sock_optval,
00172                        (socklen_t*)&sock_optval_size) != 0) {
00173             // 接続に失敗
00174             tcpclient_close(cli);
00175             return -3;
00176         }
00177 
00178         if (sock_optval != 0) {
00179             // 接続に失敗
00180             tcpclient_close(cli);
00181             return -4;
00182         }
00183 
00184         set_block_mode(cli);
00185     }
00186 #endif
00187 
00188     return 0;
00189 }
00190 
00191 
00192 void tcpclient_close(urg_tcpclient_t* cli)
00193 {
00194     if (cli->sock_desc != Invalid_desc) {
00195 #if defined(URG_WINDOWS_OS)
00196         closesocket(cli->sock_desc);
00197         //WSACleanup();
00198 #else
00199         close(cli->sock_desc);
00200 #endif
00201         cli->sock_desc = Invalid_desc;
00202     }
00203 }
00204 
00205 
00206 int tcpclient_read(urg_tcpclient_t* cli,
00207                    char* userbuf, int req_size, int timeout)
00208 {
00209     // number of data in buffer.
00210     int num_in_buf = tcpclient_buffer_data_num(cli);
00211     int sock       = cli->sock_desc;
00212     int rem_size   = req_size;  // remaining size to be sent back.
00213     int n;
00214 
00215     // copy data in buffer to user buffer and return with requested size.
00216     if (num_in_buf > 0) {
00217         n = tcpclient_buffer_read(cli, userbuf, req_size);
00218         rem_size = req_size - n;  // lacking size.
00219         if (rem_size <= 0) {
00220             return req_size;
00221         }
00222 
00223         num_in_buf = tcpclient_buffer_data_num(cli);
00224     }
00225 
00226     // data in buffer was not enough, read from socket to fill buffer,
00227     // without blocking, i.e. read from system's buffer.
00228     {
00229         char tmpbuf[BUFSIZE];
00230         // receive with non-blocking mode.
00231 #if defined(URG_WINDOWS_OS)
00232         int no_timeout = 1;
00233         setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&no_timeout, sizeof(struct timeval));
00234         n = recv(sock, tmpbuf, BUFSIZE - num_in_buf, 0);
00235 #else
00236         n = recv(sock, tmpbuf, BUFSIZE - num_in_buf, MSG_DONTWAIT);
00237 #endif
00238         if (n > 0) {
00239             tcpclient_buffer_write(cli, tmpbuf, n); // copy socket to my buffer
00240         }
00241 
00242         n = tcpclient_buffer_read(cli, &userbuf[req_size-rem_size], rem_size);
00243         // n never be greater than rem_size
00244         rem_size -= n;
00245         if (rem_size <= 0) {
00246             return req_size;
00247         }
00248     }
00249 
00250     //  lastly recv with blocking but with time out to read necessary size.
00251     {
00252 #if defined(URG_WINDOWS_OS)
00253         setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
00254                    (const char *)&timeout, sizeof(struct timeval));
00255 #else
00256         struct timeval tv;
00257         tv.tv_sec = timeout / 1000; // millisecond to seccond
00258         tv.tv_usec = (timeout % 1000) * 1000; // millisecond to microsecond
00259         setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
00260 #endif
00261         //4th arg 0:no flag
00262         n = recv(sock, &userbuf[req_size-rem_size], rem_size, 0);
00263         // n never be greater than rem_size
00264         if (n > 0) {
00265             rem_size -= n;
00266         }
00267     }
00268 
00269     return (req_size - rem_size); // last return may be less than req_size;
00270 }
00271 
00272 
00273 int tcpclient_write(urg_tcpclient_t* cli, const char* buf, int size)
00274 {
00275     // blocking if data size is larger than system's buffer.
00276     return send(cli->sock_desc, buf, size, 0);  //4th arg 0: no flag
00277 }
00278 
00279 
00280 int tcpclient_error(urg_tcpclient_t* cli, char* error_message, int max_size)
00281 {
00282     (void)cli;
00283     (void)error_message;
00284     (void)max_size;
00285 
00286     // not implemented yet.
00287 
00288     return -1;
00289 }
00290 
00291 
00292 int tcpclient_readline(urg_tcpclient_t* cli,
00293                        char* userbuf, int buf_size, int timeout)
00294 {
00295     int n = 0;
00296     int i = 0;
00297 
00298     if (cli->pushed_back > 0) {
00299         userbuf[i] = cli->pushed_back;
00300         i++;
00301         cli->pushed_back = -1;
00302     }
00303     for (; i < buf_size; ++i) {
00304         char ch;
00305         n = tcpclient_read(cli, &ch, 1, timeout);
00306         if (n <= 0) {
00307             break; // error
00308         }
00309         if (ch == '\n' || ch == '\r') {
00310             break; // success
00311         }
00312         userbuf[i] = ch;
00313     }
00314 
00315     if (i >= buf_size) { // No CR or LF found.
00316         --i;
00317         cli->pushed_back = userbuf[buf_size - 1] & 0xff;
00318         userbuf[buf_size - 1] = '\0';
00319     }
00320     userbuf[i] = '\0';
00321 
00322     if (i == 0 && n <= 0) { // error
00323         return -1;
00324     }
00325 
00326     return i; // the number of characters filled into user buffer.
00327 }


urg_c
Author(s): Satofumi Kamimura , Katsumi Kimoto, Adrian Boeing
autogenerated on Thu Jun 6 2019 19:06:57