1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-05-26 xiangxistu first version
9 */
10
11 /* Do NOT include sys/time.h in this file */
12 #include <WinSock2.h>
13 #include <WS2tcpip.h>
14 #include <rtthread.h>
15 #include <stdint.h>
16
17 #define DBG_TAG "sal.winsock"
18 #define DBG_LVL DBG_INFO
19 #include <rtdbg.h>
20
21 #include "rtt_winsock.h"
22
23 static struct sal_type_hostent sal_hostent;
24 static sal_type_ip_addr_t hostent_addr = { 0 };
25 static sal_type_ip_addr_t* hostent_addr_p = RT_NULL;
26
27 /* Important, must reserve */
28 #pragma comment( lib, "ws2_32.lib" )
29
30 /*
31 * reserve for select / poll
32 *
33 * #define WINDOWS_STACK_SIZE 2048
34 * #define WINDOWS_PRIORITY 2048
35 * #define WINDOWS_TICK 10
36 *
37 * struct poll_thread_list
38 * {
39 * int socket;
40 * rt_slist_t slist;
41 * };
42 * static rt_slist_t poll_pending_list = RT_SLIST_OBJECT_INIT(poll_pending_list);
43 *
44 **/
45
46 #define WINDOWS_PERVIOS_COMAMND \
47 do \
48 { \
49 int iResult; \
50 WSADATA wsa_data; \
51 \
52 iResult = WSAStartup(MAKEWORD(2, 2), &wsa_data); \
53 if (iResult != 0) \
54 { \
55 LOG_E("WSAStartup failed: %d\n", iResult); \
56 return -RT_ERROR; \
57 } \
58 }while(0)
59
data_sync_sockaddr(struct sal_type_sockaddr * sal,struct sockaddr ** window)60 static void data_sync_sockaddr(struct sal_type_sockaddr* sal, struct sockaddr** window)
61 {
62 /*
63 * ws2def.h
64 * typedef struct sockaddr {
65 *
66 * #if (_WIN32_WINNT < 0x0600)
67 * u_short sa_family;
68 * #else
69 * ADDRESS_FAMILY sa_family; // Address family.
70 * #endif //(_WIN32_WINNT < 0x0600)
71 *
72 * CHAR sa_data[14]; // Up to 14 bytes of direct address.
73 * } SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR;
74 *
75 ***********************************
76 * sal_socket.h
77 * struct sockaddr
78 * {
79 * uint8_t sa_len;
80 * sa_family_t sa_family;
81 * char sa_data[14];
82 * };
83 */
84 ADDRESS_FAMILY family = 0;
85 family = sal->sa_family;
86
87 *window = sal;
88 (* window)->sa_family = family;
89 }
90
win_socket(int domain,int type,int protocol)91 int win_socket(int domain, int type, int protocol)
92 {
93 WINDOWS_PERVIOS_COMAMND;
94
95 return (int)socket(domain, type, protocol);
96 }
97
win_closesocket(int s)98 int win_closesocket(int s)
99 {
100 return (int)closesocket(s);
101 }
102
win_bind(int s,const struct sal_type_sockaddr * name,sal_type_socklen_t namelen)103 int win_bind(int s, const struct sal_type_sockaddr *name, sal_type_socklen_t namelen)
104 {
105 return (int)bind(s, name, namelen);
106 }
107
win_listen(int s,int backlog)108 int win_listen(int s, int backlog)
109 {
110 return (int)listen(s, backlog);
111 }
112
win_connect(int s,const struct sal_type_sockaddr * name,sal_type_socklen_t namelen)113 int win_connect(int s, const struct sal_type_sockaddr *name, sal_type_socklen_t namelen)
114 {
115 struct sockaddr *windows_addr = RT_NULL;
116 data_sync_sockaddr(name, &windows_addr);
117
118 return (int)connect(s, windows_addr, namelen);
119 }
120
win_accept(int s,struct sal_type_sockaddr * addr,sal_type_socklen_t * addrlen)121 int win_accept(int s, struct sal_type_sockaddr *addr, sal_type_socklen_t *addrlen)
122 {
123 WINDOWS_PERVIOS_COMAMND;
124
125 return (int)accept(s, addr, addrlen);
126 }
127
win_sendto(int s,const void * data,size_t size,int flags,const struct sal_type_sockaddr * to,sal_type_socklen_t tolen)128 int win_sendto(int s, const void *data, size_t size, int flags, const struct sal_type_sockaddr *to, sal_type_socklen_t tolen)
129 {
130 return (int)sendto(s, data, size, flags, to, tolen);
131 }
132
win_recvfrom(int s,void * mem,size_t len,int flags,struct sal_type_sockaddr * from,sal_type_socklen_t * fromlen)133 int win_recvfrom(int s, void *mem, size_t len, int flags, struct sal_type_sockaddr *from, sal_type_socklen_t *fromlen)
134 {
135 return (int)recvfrom(s, mem, len, flags, from, fromlen);
136 }
137
win_getsockopt(int s,int level,int optname,void * optval,sal_type_socklen_t * optlen)138 int win_getsockopt(int s, int level, int optname, void *optval, sal_type_socklen_t *optlen)
139 {
140 return (int)getsockopt(s, level, optname, optval, optlen);
141 }
142
win_setsockopt(int s,int level,int optname,const void * optval,sal_type_socklen_t optlen)143 int win_setsockopt(int s, int level, int optname, const void *optval, sal_type_socklen_t optlen)
144 {
145 return (int)setsockopt(s, level, optname, optval, optlen);
146 }
147
win_shutdown(int s,int how)148 int win_shutdown(int s, int how)
149 {
150 return (int)shutdown(s, how);
151 }
152
win_getpeername(int s,struct sal_type_sockaddr * name,sal_type_socklen_t * namelen)153 int win_getpeername(int s, struct sal_type_sockaddr *name, sal_type_socklen_t *namelen)
154 {
155 return (int)getpeername(s, name, namelen);
156 }
157
win_getsockname(int s,struct sal_type_sockaddr * name,sal_type_socklen_t * namelen)158 int win_getsockname(int s, struct sal_type_sockaddr *name, sal_type_socklen_t *namelen)
159 {
160 return (int)getsockname(s, name, namelen);
161 }
162
win_ioctlsocket(int s,long cmd,void * arg)163 int win_ioctlsocket(int s, long cmd, void *arg)
164 {
165 return (int)ioctlsocket(s, cmd, arg);
166 }
167
168 #ifdef SAL_USING_POSIX
169 /* use windows poll, but not wait */
inet_poll(struct dfs_file * file,struct rt_pollreq * req)170 int inet_poll(struct dfs_file* file, struct rt_pollreq* req)
171 {
172 /*
173 WSAPOLLFD winpoll;
174 struct sal_socket* sal_sock;
175 int mask = 0;
176 int poll_event = 0;
177
178 sal_sock = sal_get_socket((int)file->data);
179 if (!sal_sock)
180 {
181 return -1;
182 }
183
184 winpoll.fd = sal_sock->socket;
185 poll_event &= POLLERR | POLLHUP;
186 winpoll.events = req->_key & (~poll_event);
187 poll_event = 0;
188
189 mask = WSAPoll(&winpoll, 1, 0);
190 if (mask == 0)
191 return 0;
192
193 return winpoll.revents;
194 */
195
196 return 0;
197 }
198 #endif /* SAL_USING_POSIX */
199
win_gethostbyname(const char * name)200 struct sal_type_hostent* win_gethostbyname(const char* name)
201 {
202 struct hostent *windows_hostent;
203 char** h_addr_list;
204
205 WINDOWS_PERVIOS_COMAMND;
206
207 windows_hostent = gethostbyname(name);
208
209 sal_hostent.h_name = windows_hostent->h_name;
210 sal_hostent.h_aliases = windows_hostent->h_aliases;
211 sal_hostent.h_addrtype = windows_hostent->h_addrtype;
212 sal_hostent.h_length = windows_hostent->h_length;
213 sal_hostent.h_addr_list = windows_hostent->h_addr_list;
214 hostent_addr.addr = ((struct in_addr*)windows_hostent->h_addr)->s_addr;
215 hostent_addr_p = &hostent_addr;
216 sal_hostent.h_addr_list = &hostent_addr_p;
217
218 return &sal_hostent;
219 }
220
win_getaddrinfo(const char * nodename,const char * servname,const struct sal_type_addrinfo * hints,struct sal_type_addrinfo ** res)221 int win_getaddrinfo(const char* nodename, const char* servname, const struct sal_type_addrinfo* hints, struct sal_type_addrinfo** res)
222 {
223 int port_nr = 0;
224 sal_type_ip_addr_t addr = { 0 };
225 struct sal_type_addrinfo* ai;
226 struct sal_type_sockaddr_storage* sa;
227 size_t total_size = 0;
228 size_t namelen = 0;
229 char* change_point;
230
231 if (res == RT_NULL)
232 return EAI_FAIL;
233 *res = RT_NULL;
234
235 if ((nodename == RT_NULL) && (servname == RT_NULL))
236 return EAI_NONAME;
237
238 if ((hints != RT_NULL)
239 && (hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC))
240 return EAI_FAMILY;
241
242 if (servname != RT_NULL)
243 {
244 /* service name specified: convert to port number */
245 port_nr = atoi(servname);
246 if ((port_nr <= 0) || (port_nr > 0xffff))
247 {
248 return EAI_SERVICE;
249 }
250 }
251
252 if (nodename != RT_NULL)
253 {
254 WINDOWS_PERVIOS_COMAMND;
255 struct hostent* hostent = gethostbyname(nodename);
256 if (hostent == RT_NULL)
257 return EAI_FAIL;
258 addr.addr = ((struct in_addr*)hostent->h_addr)->s_addr;
259 }
260
261 total_size = sizeof(struct sal_type_addrinfo) + sizeof(struct sal_type_sockaddr_storage);
262 if (nodename != RT_NULL)
263 {
264 namelen = strlen(nodename);
265 if (namelen > DNS_MAX_NAME_LENGTH)
266 {
267 /* invalid name length */
268 return EAI_FAIL;
269 }
270 RT_ASSERT(total_size + namelen + 1 > total_size);
271 total_size += namelen + 1;
272 }
273
274 RT_ASSERT(total_size <= sizeof(struct sal_type_addrinfo) + sizeof(struct sal_type_sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1);
275 ai = (struct sal_type_addrinfo*)rt_malloc(total_size);
276 if (ai == RT_NULL)
277 {
278 return EAI_MEMORY;
279 }
280 rt_memset(ai, 0, total_size);
281
282 /* cast through void* to get rid of alignment warnings */
283 sa = (struct sal_type_sockaddr_storage*)(void*)((uint8_t*)ai + sizeof(struct sal_type_addrinfo));
284 struct sal_type_sockaddr_in* sa4 = (struct sal_type_sockaddr_in*)sa;
285
286 sa4->sin_family = AF_INET;
287 sa4->sin_addr.sal_type_s_addr = addr.addr;
288 sa4->sin_port = htons((uint16_t)port_nr);
289
290 /* set up addrinfo */
291 if (hints != RT_NULL)
292 {
293 /* copy socktype & protocol from hints if specified */
294 ai->ai_socktype = hints->ai_socktype;
295 ai->ai_protocol = hints->ai_protocol;
296 }
297 if (nodename != RT_NULL)
298 {
299 /* copy nodename to canonname if specified */
300 ai->ai_canonname = ((char*)ai + sizeof(struct sal_type_addrinfo) + sizeof(struct sal_type_sockaddr_storage));
301 rt_memcpy(ai->ai_canonname, nodename, namelen);
302 ai->ai_canonname[namelen] = 0;
303 }
304
305 ai->ai_addrlen = sizeof(struct sal_type_sockaddr_storage);
306 ai->ai_addr = (struct sal_type_sockaddr*)sa;
307 ai->ai_family = sa4->sin_family;
308
309 *res = ai;
310
311 return 0;
312 }
313
win_freeaddrinfo(struct sal_type_addrinfo * ai)314 void win_freeaddrinfo(struct sal_type_addrinfo* ai)
315 {
316 struct sal_type_addrinfo* next;
317
318 while (ai != NULL)
319 {
320 next = ai->ai_next;
321 rt_free(ai);
322 ai = next;
323 }
324 }
325