win dont redefine _WINSOCK_DEPRECATED_NO_WARNINGS
[platform/upstream/libwebsockets.git] / lib / lws-plat-win.c
1 #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
2 #define _WINSOCK_DEPRECATED_NO_WARNINGS
3 #endif
4 #include "private-libwebsockets.h"
5
6 unsigned long long
7 time_in_microseconds()
8 {
9 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
10         FILETIME filetime;
11         ULARGE_INTEGER datetime;
12
13 #ifdef _WIN32_WCE
14         GetCurrentFT(&filetime);
15 #else
16         GetSystemTimeAsFileTime(&filetime);
17 #endif
18
19         /*
20          * As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
21          * ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
22          * prevent alignment faults on 64-bit Windows).
23          */
24         memcpy(&datetime, &filetime, sizeof(datetime));
25
26         /* Windows file times are in 100s of nanoseconds. */
27         return (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10;
28 }
29
30 #ifdef _WIN32_WCE
31 time_t time(time_t *t)
32 {
33         time_t ret = time_in_microseconds() / 1000000;
34         *t = ret;
35         return ret;
36 }
37 #endif
38
39 /* file descriptor hash management */
40
41 struct lws *
42 wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd)
43 {
44         int h = LWS_FD_HASH(fd);
45         int n = 0;
46
47         for (n = 0; n < context->fd_hashtable[h].length; n++)
48                 if (context->fd_hashtable[h].wsi[n]->sock == fd)
49                         return context->fd_hashtable[h].wsi[n];
50
51         return NULL;
52 }
53
54 int
55 insert_wsi(struct lws_context *context, struct lws *wsi)
56 {
57         int h = LWS_FD_HASH(wsi->sock);
58
59         if (context->fd_hashtable[h].length == (getdtablesize() - 1)) {
60                 lwsl_err("hash table overflow\n");
61                 return 1;
62         }
63
64         context->fd_hashtable[h].wsi[context->fd_hashtable[h].length++] = wsi;
65
66         return 0;
67 }
68
69 int
70 delete_from_fd(struct lws_context *context, lws_sockfd_type fd)
71 {
72         int h = LWS_FD_HASH(fd);
73         int n = 0;
74
75         for (n = 0; n < context->fd_hashtable[h].length; n++)
76                 if (context->fd_hashtable[h].wsi[n]->sock == fd) {
77                         while (n < context->fd_hashtable[h].length) {
78                                 context->fd_hashtable[h].wsi[n] =
79                                             context->fd_hashtable[h].wsi[n + 1];
80                                 n++;
81                         }
82                         context->fd_hashtable[h].length--;
83
84                         return 0;
85                 }
86
87         lwsl_err("Failed to find fd %d requested for "
88                  "delete in hashtable\n", fd);
89         return 1;
90 }
91
92 LWS_VISIBLE int lws_get_random(struct lws_context *context,
93                                                              void *buf, int len)
94 {
95         int n;
96         char *p = (char *)buf;
97
98         for (n = 0; n < len; n++)
99                 p[n] = (unsigned char)rand();
100
101         return n;
102 }
103
104 LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi)
105 {
106         return (int)wsi->sock_send_blocking;
107 }
108
109 LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd)
110 {
111         fd_set readfds;
112         struct timeval tv = { 0, 0 };
113
114         assert(fd->events == LWS_POLLIN);
115
116         FD_ZERO(&readfds);
117         FD_SET(fd->fd, &readfds);
118
119         return select(fd->fd + 1, &readfds, NULL, NULL, &tv);
120 }
121
122 /**
123  * lws_cancel_service() - Cancel servicing of pending websocket activity
124  * @context:    Websocket context
125  *
126  *      This function let a call to lws_service() waiting for a timeout
127  *      immediately return.
128  */
129 LWS_VISIBLE void
130 lws_cancel_service(struct lws_context *context)
131 {
132         struct lws_context_per_thread *pt = &context->pt[0];
133         int n = context->count_threads;
134
135         while (n--) {
136                 WSASetEvent(pt->events[0]);
137                 pt++;
138         }
139 }
140
141 LWS_VISIBLE void
142 lws_cancel_service_pt(struct lws *wsi)
143 {
144         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
145         WSASetEvent(pt->events[0]);
146 }
147
148 LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
149 {
150         lwsl_emit_stderr(level, line);
151 }
152
153 LWS_VISIBLE int
154 lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
155 {
156         int n;
157         unsigned int i;
158         DWORD ev;
159         WSANETWORKEVENTS networkevents;
160         struct lws_pollfd *pfd;
161         struct lws *wsi;
162         struct lws_context_per_thread *pt = &context->pt[tsi];
163
164         /* stay dead once we are dead */
165
166         if (context == NULL)
167                 return 1;
168
169         if (!context->service_tid_detected) {
170                 struct lws _lws;
171
172                 memset(&_lws, 0, sizeof(_lws));
173                 _lws.context = context;
174
175                 context->service_tid_detected = context->protocols[0].callback(
176                         &_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
177         }
178         context->service_tid = context->service_tid_detected;
179
180         for (i = 0; i < pt->fds_count; ++i) {
181                 pfd = &pt->fds[i];
182                 if (pfd->fd == pt->lserv_fd)
183                         continue;
184
185                 if (pfd->events & LWS_POLLOUT) {
186                         wsi = wsi_from_fd(context, pfd->fd);
187                         if (!wsi || wsi->sock_send_blocking)
188                                 continue;
189                         pfd->revents = LWS_POLLOUT;
190                         n = lws_service_fd(context, pfd);
191                         if (n < 0)
192                                 return -1;
193                         /* if something closed, retry this slot */
194                         if (n)
195                                 i--;
196                 }
197         }
198
199         ev = WSAWaitForMultipleEvents(pt->fds_count + 1, pt->events,
200                                       FALSE, timeout_ms, FALSE);
201         context->service_tid = 0;
202
203         if (ev == WSA_WAIT_TIMEOUT) {
204                 lws_service_fd(context, NULL);
205                 return 0;
206         }
207
208         if (ev == WSA_WAIT_EVENT_0) {
209                 WSAResetEvent(pt->events[0]);
210                 return 0;
211         }
212
213         if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + pt->fds_count)
214                 return -1;
215
216         pfd = &pt->fds[ev - WSA_WAIT_EVENT_0 - 1];
217
218         if (WSAEnumNetworkEvents(pfd->fd,
219                                  pt->events[ev - WSA_WAIT_EVENT_0],
220                                  &networkevents) == SOCKET_ERROR) {
221                 lwsl_err("WSAEnumNetworkEvents() failed with error %d\n",
222                                                                      LWS_ERRNO);
223                 return -1;
224         }
225
226         pfd->revents = (short)networkevents.lNetworkEvents;
227
228         if (pfd->revents & LWS_POLLOUT) {
229                 wsi = wsi_from_fd(context, pfd->fd);
230                 if (wsi)
231                         wsi->sock_send_blocking = 0;
232         }
233
234         return lws_service_fd(context, pfd);
235 }
236
237 LWS_VISIBLE int
238 lws_plat_service(struct lws_context *context, int timeout_ms)
239 {
240         return lws_plat_service_tsi(context, timeout_ms, 0);
241 }
242
243 LWS_VISIBLE int
244 lws_plat_set_socket_options(struct lws_context *context, lws_sockfd_type fd)
245 {
246         int optval = 1;
247         int optlen = sizeof(optval);
248         u_long optl = 1;
249         DWORD dwBytesRet;
250         struct tcp_keepalive alive;
251         struct protoent *tcp_proto;
252
253         if (context->ka_time) {
254                 /* enable keepalive on this socket */
255                 optval = 1;
256                 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
257                                              (const char *)&optval, optlen) < 0)
258                         return 1;
259
260                 alive.onoff = TRUE;
261                 alive.keepalivetime = context->ka_time;
262                 alive.keepaliveinterval = context->ka_interval;
263
264                 if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
265                                               NULL, 0, &dwBytesRet, NULL, NULL))
266                         return 1;
267         }
268
269         /* Disable Nagle */
270         optval = 1;
271         tcp_proto = getprotobyname("TCP");
272         if (!tcp_proto) {
273                 lwsl_err("getprotobyname() failed with error %d\n", LWS_ERRNO);
274                 return 1;
275         }
276
277         setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, (const char *)&optval, optlen);
278
279         /* We are nonblocking... */
280         ioctlsocket(fd, FIONBIO, &optl);
281
282         return 0;
283 }
284
285 LWS_VISIBLE void
286 lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
287 {
288 }
289
290 LWS_VISIBLE int
291 lws_plat_context_early_init(void)
292 {
293         WORD wVersionRequested;
294         WSADATA wsaData;
295         int err;
296
297         /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
298         wVersionRequested = MAKEWORD(2, 2);
299
300         err = WSAStartup(wVersionRequested, &wsaData);
301         if (!err)
302                 return 0;
303         /*
304          * Tell the user that we could not find a usable
305          * Winsock DLL
306          */
307         lwsl_err("WSAStartup failed with error: %d\n", err);
308
309         return 1;
310 }
311
312 LWS_VISIBLE void
313 lws_plat_context_early_destroy(struct lws_context *context)
314 {
315         struct lws_context_per_thread *pt = &context->pt[0];
316         int n = context->count_threads;
317
318         while (n--) {
319                 if (pt->events) {
320                         WSACloseEvent(pt->events[0]);
321                         lws_free(pt->events);
322                 }
323                 pt++;
324         }
325 }
326
327 LWS_VISIBLE void
328 lws_plat_context_late_destroy(struct lws_context *context)
329 {
330         int n;
331
332         for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
333                 if (context->fd_hashtable[n].wsi)
334                         lws_free(context->fd_hashtable[n].wsi);
335         }
336
337         WSACleanup();
338 }
339
340 LWS_VISIBLE LWS_EXTERN int
341 lws_interface_to_sa(int ipv6,
342                 const char *ifname, struct sockaddr_in *addr, size_t addrlen)
343 {
344         long long address = inet_addr(ifname);
345
346         if (address == INADDR_NONE) {
347                 struct hostent *entry = gethostbyname(ifname);
348                 if (entry)
349                         address = ((struct in_addr *)entry->h_addr_list[0])->s_addr;
350         }
351
352         if (address == INADDR_NONE)
353                 return -1;
354
355         addr->sin_addr.s_addr = (unsigned long)address;
356
357         return 0;
358 }
359
360 LWS_VISIBLE void
361 lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
362 {
363         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
364
365         pt->fds[pt->fds_count++].revents = 0;
366         pt->events[pt->fds_count] = WSACreateEvent();
367         WSAEventSelect(wsi->sock, pt->events[pt->fds_count], LWS_POLLIN);
368 }
369
370 LWS_VISIBLE void
371 lws_plat_delete_socket_from_fds(struct lws_context *context,
372                                                 struct lws *wsi, int m)
373 {
374         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
375
376         WSACloseEvent(pt->events[m + 1]);
377         pt->events[m + 1] = pt->events[pt->fds_count--];
378 }
379
380 LWS_VISIBLE void
381 lws_plat_service_periodic(struct lws_context *context)
382 {
383 }
384
385 LWS_VISIBLE int
386 lws_plat_change_pollfd(struct lws_context *context,
387                       struct lws *wsi, struct lws_pollfd *pfd)
388 {
389         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
390         long networkevents = LWS_POLLHUP;
391
392         if ((pfd->events & LWS_POLLIN))
393                 networkevents |= LWS_POLLIN;
394
395         if ((pfd->events & LWS_POLLOUT))
396                 networkevents |= LWS_POLLOUT;
397
398         if (WSAEventSelect(wsi->sock,
399                         pt->events[wsi->position_in_fds_table + 1],
400                                                networkevents) != SOCKET_ERROR)
401                 return 0;
402
403         lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO);
404
405         return 1;
406 }
407
408 LWS_VISIBLE const char *
409 lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
410 {
411         WCHAR *buffer;
412         DWORD bufferlen = cnt;
413         BOOL ok = FALSE;
414
415         buffer = lws_malloc(bufferlen);
416         if (!buffer) {
417                 lwsl_err("Out of memory\n");
418                 return NULL;
419         }
420
421         if (af == AF_INET) {
422                 struct sockaddr_in srcaddr;
423                 bzero(&srcaddr, sizeof(srcaddr));
424                 srcaddr.sin_family = AF_INET;
425                 memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
426
427                 if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
428                         ok = TRUE;
429 #ifdef LWS_USE_IPV6
430         } else if (af == AF_INET6) {
431                 struct sockaddr_in6 srcaddr;
432                 bzero(&srcaddr, sizeof(srcaddr));
433                 srcaddr.sin6_family = AF_INET6;
434                 memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));
435
436                 if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
437                         ok = TRUE;
438 #endif
439         } else
440                 lwsl_err("Unsupported type\n");
441
442         if (!ok) {
443                 int rv = WSAGetLastError();
444                 lwsl_err("WSAAddressToString() : %d\n", rv);
445         } else {
446                 if (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) <= 0)
447                         ok = FALSE;
448         }
449
450         lws_free(buffer);
451         return ok ? dst : NULL;
452 }
453
454 static lws_filefd_type
455 _lws_plat_file_open(struct lws *wsi, const char *filename,
456                     unsigned long *filelen, int flags)
457 {
458         HANDLE ret;
459         WCHAR buf[MAX_PATH];
460
461         (void)wsi;
462         MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
463         if ((flags & 7) == _O_RDONLY) {
464                 ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
465                           NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
466         } else {
467                 lwsl_err("%s: open for write not implemented\n", __func__);
468                 *filelen = 0;
469                 return LWS_INVALID_FILE;
470         }
471
472         if (ret != LWS_INVALID_FILE)
473                 *filelen = GetFileSize(ret, NULL);
474
475         return ret;
476 }
477
478 static int
479 _lws_plat_file_close(struct lws *wsi, lws_filefd_type fd)
480 {
481         (void)wsi;
482
483         CloseHandle((HANDLE)fd);
484
485         return 0;
486 }
487
488 static unsigned long
489 _lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset)
490 {
491         (void)wsi;
492
493         return SetFilePointer((HANDLE)fd, offset, NULL, FILE_CURRENT);
494 }
495
496 static int
497 _lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
498                     unsigned char* buf, unsigned long len)
499 {
500         DWORD _amount;
501
502         (void *)wsi;
503         if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &_amount, NULL)) {
504                 *amount = 0;
505
506                 return 1;
507         }
508
509         *amount = (unsigned long)_amount;
510
511         return 0;
512 }
513
514 static int
515 _lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
516                      unsigned char* buf, unsigned long len)
517 {
518         (void)wsi;
519         (void)fd;
520         (void)amount;
521         (void)buf;
522         (void)len;
523
524         lwsl_err("%s: not implemented yet on this platform\n", __func__);
525
526         return -1;
527 }
528
529 LWS_VISIBLE int
530 lws_plat_init(struct lws_context *context,
531               struct lws_context_creation_info *info)
532 {
533         struct lws_context_per_thread *pt = &context->pt[0];
534         int i, n = context->count_threads;
535
536         for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
537                 context->fd_hashtable[i].wsi =
538                         lws_zalloc(sizeof(struct lws*) * context->max_fds);
539
540                 if (!context->fd_hashtable[i].wsi)
541                         return -1;
542         }
543
544         while (n--) {
545                 pt->events = lws_malloc(sizeof(WSAEVENT) *
546                                         (context->fd_limit_per_thread + 1));
547                 if (pt->events == NULL) {
548                         lwsl_err("Unable to allocate events array for %d connections\n",
549                                         context->fd_limit_per_thread + 1);
550                         return 1;
551                 }
552
553                 pt->fds_count = 0;
554                 pt->events[0] = WSACreateEvent();
555
556                 pt++;
557         }
558
559         context->fd_random = 0;
560
561         context->fops.open      = _lws_plat_file_open;
562         context->fops.close     = _lws_plat_file_close;
563         context->fops.seek_cur  = _lws_plat_file_seek_cur;
564         context->fops.read      = _lws_plat_file_read;
565         context->fops.write     = _lws_plat_file_write;
566
567         return 0;
568 }