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