• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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