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
TimerCountdown(Timer * timer,unsigned int timeout)43 void TimerCountdown(Timer* timer, unsigned int timeout)
44 {
45 struct timeval now;
46 gettimeofday(&now, NULL);
47 struct timeval interval = {timeout, 0};
48 timeradd(&now, &interval, &timer->end_time);
49 }
50
51
TimerLeftMS(Timer * timer)52 int TimerLeftMS(Timer* timer)
53 {
54 struct timeval now, res;
55 gettimeofday(&now, NULL);
56 timersub(&timer->end_time, &now, &res);
57 //printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
58 return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
59 }
60
61
linux_read(Network * n,unsigned char * buffer,int len,int timeout_ms)62 int linux_read(Network* n, unsigned char* buffer, int len, int timeout_ms)
63 {
64 struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
65 if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
66 {
67 interval.tv_sec = 0;
68 interval.tv_usec = 100;
69 }
70
71 setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
72
73 int bytes = 0;
74 while (bytes < len)
75 {
76 int rc = recv(n->my_socket, &buffer[bytes], (size_t)(len - bytes), 0);
77 if (rc == -1)
78 {
79 if (errno != EAGAIN && errno != EWOULDBLOCK)
80 bytes = -1;
81 break;
82 }
83 else if (rc == 0)
84 {
85 bytes = 0;
86 break;
87 }
88 else
89 bytes += rc;
90 }
91 return bytes;
92 }
93
94
linux_write(Network * n,unsigned char * buffer,int len,int timeout_ms)95 int linux_write(Network* n, unsigned char* buffer, int len, int timeout_ms)
96 {
97 struct timeval tv;
98
99 tv.tv_sec = 0; /* 30 Secs Timeout */
100 tv.tv_usec = timeout_ms * 1000; // Not init'ing this can cause strange errors
101
102 setsockopt(n->my_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,sizeof(struct timeval));
103 int rc = write(n->my_socket, buffer, len);
104 return rc;
105 }
106
107
NetworkInit(Network * n)108 void NetworkInit(Network* n)
109 {
110 n->my_socket = 0;
111 n->mqttread = linux_read;
112 n->mqttwrite = linux_write;
113 }
114
115
NetworkConnect(Network * n,char * addr,int port)116 int NetworkConnect(Network* n, char* addr, int port)
117 {
118 int type = SOCK_STREAM;
119 struct sockaddr_in address;
120 int rc = -1;
121 sa_family_t family = AF_INET;
122 struct addrinfo *result = NULL;
123 struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
124
125 if ((rc = getaddrinfo(addr, NULL, &hints, &result)) == 0)
126 {
127 struct addrinfo* res = result;
128
129 /* prefer ip4 addresses */
130 while (res)
131 {
132 if (res->ai_family == AF_INET)
133 {
134 result = res;
135 break;
136 }
137 res = res->ai_next;
138 }
139
140 if (result->ai_family == AF_INET)
141 {
142 address.sin_port = htons(port);
143 address.sin_family = family = AF_INET;
144 address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
145 }
146 else
147 rc = -1;
148
149 freeaddrinfo(result);
150 }
151
152 if (rc == 0)
153 {
154 n->my_socket = socket(family, type, 0);
155 if (n->my_socket != -1)
156 rc = connect(n->my_socket, (struct sockaddr*)&address, sizeof(address));
157 else
158 rc = -1;
159 }
160
161 return rc;
162 }
163
164
NetworkDisconnect(Network * n)165 void NetworkDisconnect(Network* n)
166 {
167 close(n->my_socket);
168 }
169