• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2014 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  *    Ian Craggs - initial API and implementation and/or initial documentation
15  *    Sergio R. Caprile - "commonalization" from prior samples and/or documentation extension
16  *******************************************************************************/
17 
18 #include <sys/types.h>
19 
20 #if !defined(SOCKET_ERROR)
21 	/** error in socket operation */
22 	#define SOCKET_ERROR -1
23 #endif
24 
25 #if defined(WIN32)
26 /* default on Windows is 64 - increase to make Linux and Windows the same */
27 #define FD_SETSIZE 1024
28 #include <winsock2.h>
29 #include <ws2tcpip.h>
30 #define MAXHOSTNAMELEN 256
31 #define EAGAIN WSAEWOULDBLOCK
32 #define EINTR WSAEINTR
33 #define EINVAL WSAEINVAL
34 #define EINPROGRESS WSAEINPROGRESS
35 #define EWOULDBLOCK WSAEWOULDBLOCK
36 #define ENOTCONN WSAENOTCONN
37 #define ECONNRESET WSAECONNRESET
38 #define ioctl ioctlsocket
39 #define socklen_t int
40 #else
41 #define INVALID_SOCKET SOCKET_ERROR
42 #include <sys/socket.h>
43 #include <sys/param.h>
44 #include <sys/time.h>
45 #include <netinet/in.h>
46 #include <netinet/tcp.h>
47 #include <arpa/inet.h>
48 #include <netdb.h>
49 #include <stdio.h>
50 #include <unistd.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #endif
56 
57 #if defined(WIN32)
58 #include <Iphlpapi.h>
59 #else
60 #include <sys/ioctl.h>
61 #include <net/if.h>
62 #endif
63 
64 /**
65 This simple low-level implementation assumes a single connection for a single thread. Thus, a static
66 variable is used for that connection.
67 On other scenarios, the user must solve this by taking into account that the current implementation of
68 MQTTPacket_read() has a function pointer for a function call to get the data to a buffer, but no provisions
69 to know the caller or other indicator (the socket id): int (*getfn)(unsigned char*, int)
70 */
71 static int mysock = INVALID_SOCKET;
72 
73 
transport_sendPacketBuffer(int sock,unsigned char * buf,int buflen)74 int transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen)
75 {
76 	int rc = 0;
77 	rc = write(sock, buf, buflen);
78 	return rc;
79 }
80 
81 
transport_getdata(unsigned char * buf,int count)82 int transport_getdata(unsigned char* buf, int count)
83 {
84 	int rc = recv(mysock, buf, count, 0);
85 	//printf("received %d bytes count %d\n", rc, (int)count);
86 	return rc;
87 }
88 
transport_getdatanb(void * sck,unsigned char * buf,int count)89 int transport_getdatanb(void *sck, unsigned char* buf, int count)
90 {
91 	int sock = *((int *)sck); 	/* sck: pointer to whatever the system may use to identify the transport */
92 	/* this call will return after the timeout set on initialization if no bytes;
93 	   in your system you will use whatever you use to get whichever outstanding
94 	   bytes your socket equivalent has ready to be extracted right now, if any,
95 	   or return immediately */
96 	int rc = recv(sock, buf, count, 0);
97 	if (rc == -1) {
98 		/* check error conditions from your system here, and return -1 */
99 		return 0;
100 	}
101 	return rc;
102 }
103 
104 /**
105 return >=0 for a socket descriptor, <0 for an error code
106 @todo Basically moved from the sample without changes, should accomodate same usage for 'sock' for clarity,
107 removing indirections
108 */
transport_open(char * addr,int port)109 int transport_open(char* addr, int port)
110 {
111 int* sock = &mysock;
112 	int type = SOCK_STREAM;
113 	struct sockaddr_in address;
114 #if defined(AF_INET6)
115 	struct sockaddr_in6 address6;
116 #endif
117 	int rc = -1;
118 #if defined(WIN32)
119 	short family;
120 #else
121 	sa_family_t family = AF_INET;
122 #endif
123 	struct addrinfo *result = NULL;
124 	struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL};
125 	static struct timeval tv;
126 
127 	*sock = -1;
128 	if (addr[0] == '[')
129 	  ++addr;
130 
131 	if ((rc = getaddrinfo(addr, NULL, &hints, &result)) == 0)
132 	{
133 		struct addrinfo* res = result;
134 
135 		/* prefer ip4 addresses */
136 		while (res)
137 		{
138 			if (res->ai_family == AF_INET)
139 			{
140 				result = res;
141 				break;
142 			}
143 			res = res->ai_next;
144 		}
145 
146 #if defined(AF_INET6)
147 		if (result->ai_family == AF_INET6)
148 		{
149 			address6.sin6_port = htons(port);
150 			address6.sin6_family = family = AF_INET6;
151 			address6.sin6_addr = ((struct sockaddr_in6*)(result->ai_addr))->sin6_addr;
152 		}
153 		else
154 #endif
155 		if (result->ai_family == AF_INET)
156 		{
157 			address.sin_port = htons(port);
158 			address.sin_family = family = AF_INET;
159 			address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr;
160 		}
161 		else
162 			rc = -1;
163 
164 		freeaddrinfo(result);
165 	}
166 
167 	if (rc == 0)
168 	{
169 		*sock =	socket(family, type, 0);
170 		if (*sock != -1)
171 		{
172 #if defined(NOSIGPIPE)
173 			int opt = 1;
174 
175 			if (setsockopt(*sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0)
176 				Log(TRACE_MIN, -1, "Could not set SO_NOSIGPIPE for socket %d", *sock);
177 #endif
178 
179 			if (family == AF_INET)
180 				rc = connect(*sock, (struct sockaddr*)&address, sizeof(address));
181 	#if defined(AF_INET6)
182 			else
183 				rc = connect(*sock, (struct sockaddr*)&address6, sizeof(address6));
184 	#endif
185 		}
186 	}
187 	if (mysock == INVALID_SOCKET)
188 		return rc;
189 
190 	tv.tv_sec = 1;  /* 1 second Timeout */
191 	tv.tv_usec = 0;
192 	setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
193 	return mysock;
194 }
195 
transport_close(int sock)196 int transport_close(int sock)
197 {
198 int rc;
199 
200 	rc = shutdown(sock, SHUT_WR);
201 	rc = recv(sock, NULL, (size_t)0, 0);
202 	rc = close(sock);
203 
204 	return rc;
205 }
206