1 /*******************************************************************************
2 * Copyright (c) 2014, 2017 IBM Corp.
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * and Eclipse Distribution License v1.0 which accompany this distribution.
7 *
8 * The Eclipse Public License is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 * and the Eclipse Distribution License is available at
11 * http://www.eclipse.org/org/documents/edl-v10.php.
12 *
13 * Contributors:
14 * Allan Stockdill-Mander - initial API and implementation and/or initial documentation
15 * Ian Craggs - return codes from linux_read
16 *******************************************************************************/
17
18 #include "MQTTLinux.h"
19
TimerInit(Timer * timer)20 void TimerInit(Timer* timer)
21 {
22 timer->end_time = (struct timeval){0, 0};
23 }
24
TimerIsExpired(Timer * timer)25 char TimerIsExpired(Timer* timer)
26 {
27 struct timeval now, res;
28 gettimeofday(&now, NULL);
29 timersub(&timer->end_time, &now, &res);
30 return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
31 }
32
33
TimerCountdownMS(Timer * timer,unsigned int timeout)34 void TimerCountdownMS(Timer* timer, unsigned int timeout)
35 {
36 struct timeval now;
37 gettimeofday(&now, NULL);
38 struct timeval interval = {timeout / 1000, (timeout % 1000) * 1000};
39 timeradd(&now, &interval, &timer->end_time);
40 }
41
42
TimerAddSecond(Timer * timer,unsigned int time)43 void TimerAddSecond(Timer* timer, unsigned int time)
44 {
45 struct timeval interval = {time, 0};
46 timeradd(&timer->end_time, &interval, &timer->end_time);
47 }
48
49
TimerCountdown(Timer * timer,unsigned int timeout)50 void TimerCountdown(Timer* timer, unsigned int timeout)
51 {
52 struct timeval now;
53 gettimeofday(&now, NULL);
54 struct timeval interval = {timeout, 0};
55 timeradd(&now, &interval, &timer->end_time);
56 }
57
58
TimerLeftMS(Timer * timer)59 int TimerLeftMS(Timer* timer)
60 {
61 struct timeval now, res;
62 gettimeofday(&now, NULL);
63 timersub(&timer->end_time, &now, &res);
64 //printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
65 return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
66 }
67
68
linux_read(Network * n,unsigned char * buffer,int len,int timeout_ms)69 int linux_read(Network* n, unsigned char* buffer, int len, int timeout_ms)
70 {
71 struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
72 if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
73 {
74 interval.tv_sec = 0;
75 interval.tv_usec = 100;
76 }
77 setsockopt(n->my_socket, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int));
78 setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
79 Timer timer;
80 TimerInit(&timer);
81 TimerCountdownMS(&timer, timeout_ms);
82 int bytes = 0;
83 int rc = 0;
84 while (bytes < len)
85 {
86 rc = recv(n->my_socket, &buffer[bytes], (size_t)(len - bytes), 0);
87 if (rc == -1)
88 {
89 if (errno != EAGAIN && errno != EWOULDBLOCK){
90 bytes = -1;
91 break;
92 }
93 if (TimerIsExpired(&timer)){
94 // LogDebug("linux_read timeout...");
95 break;
96 }
97 continue;
98 }
99 else if (rc == 0)
100 {
101 bytes = 0;
102 break;
103 }
104 else{
105 TimerCountdownMS(&timer, timeout_ms);
106 bytes += rc;
107 }
108 }
109 return bytes;
110 }
111
112
linux_write(Network * n,unsigned char * buffer,int len,int timeout_ms)113 int linux_write(Network* n, unsigned char* buffer, int len, int timeout_ms)
114 {
115 struct timeval interval;
116 Timer timer;
117 TimerInit(&timer);
118 TimerCountdownMS(&timer, timeout_ms);
119 int rc = 0;
120 setsockopt(n->my_socket, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int));
121 setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&interval,sizeof(struct timeval));
122 while (rc < len && !TimerIsExpired(&timer)) {
123 interval.tv_sec = 0; /* 30 Secs Timeout */
124 interval.tv_usec = timeout_ms * 1000; // Not init'ing this can cause strange errors
125 rc = write(n->my_socket, buffer, len);
126 if (rc == -1) {
127 if (errno != EAGAIN && errno != EWOULDBLOCK) {
128 if (errno != EPIPE) {
129 LogDebug("fatal error: write buffer error,errorno = %{public}d", errno);
130 break;
131 }
132 }
133 continue;
134 }
135 }
136 return rc;
137 }
138
139
NetworkInit(Network * n)140 void NetworkInit(Network* n)
141 {
142 n->my_socket = 0;
143 n->mqttread = linux_read;
144 n->mqttwrite = linux_write;
145 }
146
147
NetworkConnect(Network * n,char * addr,int port)148 int NetworkConnect(Network* n, char* addr, int port)
149 {
150 int type = SOCK_STREAM;
151 struct sockaddr_in address;
152 int rc = -1;
153 sa_family_t family = AF_INET;
154 struct addrinfo *result = NULL;
155 struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
156
157 if ((rc = getaddrinfo(addr, NULL, &hints, &result)) == 0)
158 {
159 struct addrinfo* res = result;
160
161 /* prefer ip4 addresses */
162 while (res)
163 {
164 if (res->ai_family == AF_INET)
165 {
166 result = res;
167 break;
168 }
169 res = res->ai_next;
170 }
171
172 if (result->ai_family == AF_INET)
173 {
174 address.sin_port = htons(port);
175 address.sin_family = family = AF_INET;
176 address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
177 }
178 else
179 rc = -1;
180
181 freeaddrinfo(result);
182 }
183
184 if (rc == 0)
185 {
186 n->my_socket = socket(family, type, 0);
187 if (n->my_socket != -1) {
188 fcntl(n->my_socket, F_SETFL, fcntl(n->my_socket, F_GETFL) | O_NONBLOCK);
189 rc = connect(n->my_socket, (struct sockaddr*)&address, sizeof(address));
190 if (rc == 0 || (rc != 0 && errno == EINPROGRESS)) {
191 rc = 0;
192 int retval;
193 fd_set set;
194 FD_ZERO(&set);
195 FD_SET(n->my_socket, &set);
196 struct timeval timeo = { 2, 0};
197 retval = select(n->my_socket + 1, NULL, &set, NULL, &timeo);
198 socklen_t len = sizeof(timeo);
199 if (retval == -1) {
200 return -1;
201 } else if(retval == 0) {
202 LogDebug("connect timeout");
203 return -1;
204 }
205 return 0;
206 }
207 }
208 else
209 rc = -1;
210 }
211
212 return rc;
213 }
214
215
NetworkDisconnect(Network * n)216 void NetworkDisconnect(Network* n)
217 {
218 close(n->my_socket);
219 }
220