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