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