blob: 1fa9090d6fb9c2df136e0e424eafd82f8442c863 [file] [log] [blame]
Keun young Park5eba08f2012-03-26 18:31:29 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16#include <arpa/inet.h>
17#include <errno.h>
18#include <strings.h>
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <unistd.h>
22#include <fcntl.h>
23
24#include "Log.h"
25
26#include "ClientSocket.h"
27
28ClientSocket::ClientSocket()
29 : mSocket(-1),
30 mTimeoutEnabled(false)
31{
32
33}
34
35ClientSocket::~ClientSocket()
36{
37 release();
38}
39
40bool ClientSocket::init(const char* hostIp, int port, bool enableTimeout)
41{
42 LOGD("ClientSocket::init");
43 mSocket = socket(AF_INET, SOCK_STREAM, 0);
44 if (mSocket < 0) {
45 LOGE("cannot open socket %d", errno);
46 return false;
47 }
48 int reuse = 1;
49 if (setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
50 LOGE("setsockopt error %d", errno);
51 release();
52 return false;
53 }
54
55 struct sockaddr_in serverAddr;
56 bzero((char*)&serverAddr, sizeof(serverAddr));
57 serverAddr.sin_family = AF_INET;
58 serverAddr.sin_port = htons(port);
59 if (inet_pton(AF_INET, hostIp, &serverAddr.sin_addr) != 1) {
60 release();
61 LOGE("inet_pton failed %d", errno);
62 return false;
63 }
64 if (connect(mSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
65 release();
66 LOGE("cannot connect socket %d", errno);
67 return false;
68 }
69 mTimeoutEnabled = enableTimeout;
70 return true;
71}
72
73const int ZERO_RW_SLEEP_TIME_US = 10;
74
75// make non-blocking mode only during read. This allows supporting time-out for read
76bool ClientSocket::readData(char* data, int len, int timeoutInMs)
77{
78 bool useTimeout = (mTimeoutEnabled && (timeoutInMs > 0));
79 int flOriginal = 0;
80 int timeInSec = 0;
81 int timeInUs = 0;
82 if (useTimeout) {
83 flOriginal = fcntl(mSocket, F_GETFL,0);
84 if (flOriginal == -1) {
85 LOGE("fcntl error %d", errno);
86 return false;
87 }
88 if (fcntl(mSocket, F_SETFL, flOriginal | O_NONBLOCK) == -1) {
89 LOGE("fcntl error %d", errno);
90 return false;
91 }
92 timeInSec = timeoutInMs / 1000;
93 timeInUs = (timeoutInMs % 1000) * 1000;
94 }
95 bool result = true;
96 int read;
97 int toRead = len;
98 while (toRead > 0) {
99 if (useTimeout) {
100 fd_set rfds;
101 struct timeval tv;
102 tv.tv_sec = timeInSec;
103 tv.tv_usec = timeInUs;
104 FD_ZERO(&rfds);
105 FD_SET(mSocket, &rfds);
106 if (select(mSocket + 1, &rfds, NULL, NULL, &tv) == -1) {
107 LOGE("select failed");
108 result = false;
109 break;
110 }
111 if (!FD_ISSET(mSocket, &rfds)) {
112 LOGE("socket read timeout");
113 result = false;
114 break;
115 }
116 }
117 read = recv(mSocket, (void*)data, toRead, 0);
118 if (read > 0) {
119 toRead -= read;
120 data += read;
121 } else if (read == 0) {
122 // in blocking mode, zero read mean's peer closed.
123 // in non-blocking mode, select said that there is data. so it should not happen
124 LOGE("zero read, peer closed or what?, nonblocking: %d", useTimeout);
125 result = false;
126 break;
127 } else {
128 LOGE("recv returned %d", read);
129 result = false;
130 break;
131 }
132 }
133 if (useTimeout) {
134 fcntl(mSocket, F_SETFL, flOriginal); // now blocking again
135 }
136 return result;
137}
138
139bool ClientSocket::sendData(const char* data, int len)
140{
141 int sent;
142 int toSend = len;
143 while (toSend > 0) {
144 sent = send(mSocket, (void*)data, (size_t)toSend, 0);
145 if (sent > 0) {
146 toSend -= sent;
147 data += sent;
148 } else if (sent == 0) { // no more buffer?
149 usleep(ZERO_RW_SLEEP_TIME_US); // just wait
150 } else {
151 LOGE("send returned %d, error %d", sent, errno);
152 return false;
153 }
154 }
155 return true;
156}
157
158void ClientSocket::release()
159{
160 if (mSocket != -1) {
161 close(mSocket);
162 mSocket = -1;
163 }
164}