win32 more build fixes
[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 /**
126  * lws_cancel_service() - Cancel servicing of pending websocket activity
127  * @context:    Websocket context
128  *
129  *      This function let a call to lws_service() waiting for a timeout
130  *      immediately return.
131  */
132 LWS_VISIBLE void
133 lws_cancel_service(struct lws_context *context)
134 {
135         struct lws_context_per_thread *pt = &context->pt[0];
136         int n = context->count_threads;
137
138         while (n--) {
139                 WSASetEvent(pt->events[0]);
140                 pt++;
141         }
142 }
143
144 LWS_VISIBLE void
145 lws_cancel_service_pt(struct lws *wsi)
146 {
147         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
148         WSASetEvent(pt->events[0]);
149 }
150
151 LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
152 {
153         lwsl_emit_stderr(level, line);
154 }
155
156 LWS_VISIBLE int
157 lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
158 {
159         struct lws_context_per_thread *pt = &context->pt[tsi];
160         WSANETWORKEVENTS networkevents;
161         struct lws_pollfd *pfd;
162         struct lws *wsi;
163         unsigned int i;
164         DWORD ev;
165         int n, m;
166
167         /* stay dead once we are dead */
168         if (context == NULL)
169                 return 1;
170
171         if (!context->service_tid_detected) {
172                 struct lws _lws;
173
174                 memset(&_lws, 0, sizeof(_lws));
175                 _lws.context = context;
176
177                 context->service_tid_detected = context->vhost_list->
178                         protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID,
179                                               NULL, NULL, 0);
180         }
181         context->service_tid = context->service_tid_detected;
182
183         if (timeout_ms < 0)
184                 goto faked_service;
185
186         for (i = 0; i < pt->fds_count; ++i) {
187                 pfd = &pt->fds[i];
188
189                 if (!(pfd->events & LWS_POLLOUT))
190                         continue;
191
192                 wsi = wsi_from_fd(context, pfd->fd);
193                 if (wsi->listener)
194                         continue;
195                 if (!wsi || wsi->sock_send_blocking)
196                         continue;
197                 pfd->revents = LWS_POLLOUT;
198                 n = lws_service_fd(context, pfd);
199                 if (n < 0)
200                         return -1;
201                 /* if something closed, retry this slot */
202                 if (n)
203                         i--;
204         }
205
206         /* if we know something needs service already, don't wait in poll */
207         timeout_ms = lws_service_adjust_timeout(context, timeout_ms, tsi);
208
209         ev = WSAWaitForMultipleEvents(pt->fds_count + 1, pt->events,
210                                       FALSE, timeout_ms, FALSE);
211         context->service_tid = 0;
212
213         if (ev == WSA_WAIT_TIMEOUT) {
214                 lws_service_fd(context, NULL);
215                 return 0;
216         }
217
218         if (ev == WSA_WAIT_EVENT_0) {
219                 WSAResetEvent(pt->events[0]);
220                 return 0;
221         }
222
223         if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + pt->fds_count)
224                 return -1;
225
226         pfd = &pt->fds[ev - WSA_WAIT_EVENT_0 - 1];
227
228         /* eh... is one event at a time the best windows can do? */
229
230         if (WSAEnumNetworkEvents(pfd->fd, pt->events[ev - WSA_WAIT_EVENT_0],
231                                  &networkevents) == SOCKET_ERROR) {
232                 lwsl_err("WSAEnumNetworkEvents() failed with error %d\n",
233                                                                      LWS_ERRNO);
234                 return -1;
235         }
236
237         pfd->revents = (short)networkevents.lNetworkEvents;
238
239         if (pfd->revents & LWS_POLLOUT) {
240                 wsi = wsi_from_fd(context, pfd->fd);
241                 if (wsi)
242                         wsi->sock_send_blocking = 0;
243         }
244
245 faked_service:
246
247         /* if someone faked their LWS_POLLIN, then go through all active fds */
248
249         if (lws_service_flag_pending(context, tsi)) {
250                 /* any socket with events to service? */
251                 for (n = 0; n < (int)pt->fds_count; n++) {
252                         if (!pt->fds[n].revents)
253                                 continue;
254
255                         m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
256                         if (m < 0)
257                                 return -1;
258                         /* if something closed, retry this slot */
259                         if (m)
260                                 n--;
261                 }
262                 return 0;
263         }
264
265         if (timeout_ms < 0)
266                 return 0;
267
268         /* otherwise just do the one... must be a way to improve that... */
269
270         return lws_service_fd_tsi(context, pfd, tsi);
271 }
272
273 LWS_VISIBLE int
274 lws_plat_service(struct lws_context *context, int timeout_ms)
275 {
276         return lws_plat_service_tsi(context, timeout_ms, 0);
277 }
278
279 LWS_VISIBLE int
280 lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd)
281 {
282         int optval = 1;
283         int optlen = sizeof(optval);
284         u_long optl = 1;
285         DWORD dwBytesRet;
286         struct tcp_keepalive alive;
287         int protonbr;
288 #ifndef _WIN32_WCE
289         struct protoent *tcp_proto;
290 #endif
291
292         if (vhost->ka_time) {
293                 /* enable keepalive on this socket */
294                 optval = 1;
295                 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
296                                              (const char *)&optval, optlen) < 0)
297                         return 1;
298
299                 alive.onoff = TRUE;
300                 alive.keepalivetime = vhost->ka_time;
301                 alive.keepaliveinterval = vhost->ka_interval;
302
303                 if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
304                                               NULL, 0, &dwBytesRet, NULL, NULL))
305                         return 1;
306         }
307
308         /* Disable Nagle */
309         optval = 1;
310 #ifndef _WIN32_WCE
311         tcp_proto = getprotobyname("TCP");
312         if (!tcp_proto) {
313                 lwsl_err("getprotobyname() failed with error %d\n", LWS_ERRNO);
314                 return 1;
315         }
316         protonbr = tcp_proto->p_proto;
317 #else
318         protonbr = 6;
319 #endif
320
321         setsockopt(fd, protonbr, TCP_NODELAY, (const char *)&optval, optlen);
322
323         /* We are nonblocking... */
324         ioctlsocket(fd, FIONBIO, &optl);
325
326         return 0;
327 }
328
329 LWS_VISIBLE void
330 lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
331 {
332 }
333
334 LWS_VISIBLE int
335 lws_plat_context_early_init(void)
336 {
337         WORD wVersionRequested;
338         WSADATA wsaData;
339         int err;
340
341         /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
342         wVersionRequested = MAKEWORD(2, 2);
343
344         err = WSAStartup(wVersionRequested, &wsaData);
345         if (!err)
346                 return 0;
347         /*
348          * Tell the user that we could not find a usable
349          * Winsock DLL
350          */
351         lwsl_err("WSAStartup failed with error: %d\n", err);
352
353         return 1;
354 }
355
356 LWS_VISIBLE void
357 lws_plat_context_early_destroy(struct lws_context *context)
358 {
359         struct lws_context_per_thread *pt = &context->pt[0];
360         int n = context->count_threads;
361
362         while (n--) {
363                 if (pt->events) {
364                         WSACloseEvent(pt->events[0]);
365                         lws_free(pt->events);
366                 }
367                 pt++;
368         }
369 }
370
371 LWS_VISIBLE void
372 lws_plat_context_late_destroy(struct lws_context *context)
373 {
374         int n;
375
376         for (n = 0; n < FD_HASHTABLE_MODULUS; n++) {
377                 if (context->fd_hashtable[n].wsi)
378                         lws_free(context->fd_hashtable[n].wsi);
379         }
380
381         WSACleanup();
382 }
383
384 LWS_VISIBLE LWS_EXTERN int
385 lws_interface_to_sa(int ipv6,
386                 const char *ifname, struct sockaddr_in *addr, size_t addrlen)
387 {
388         long long address = inet_addr(ifname);
389
390         if (address == INADDR_NONE) {
391                 struct hostent *entry = gethostbyname(ifname);
392                 if (entry)
393                         address = ((struct in_addr *)entry->h_addr_list[0])->s_addr;
394         }
395
396         if (address == INADDR_NONE)
397                 return -1;
398
399         addr->sin_addr.s_addr = (unsigned long)address;
400
401         return 0;
402 }
403
404 LWS_VISIBLE void
405 lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
406 {
407         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
408
409         pt->fds[pt->fds_count++].revents = 0;
410         pt->events[pt->fds_count] = WSACreateEvent();
411         WSAEventSelect(wsi->sock, pt->events[pt->fds_count],
412                        LWS_POLLIN | LWS_POLLHUP);
413 }
414
415 LWS_VISIBLE void
416 lws_plat_delete_socket_from_fds(struct lws_context *context,
417                                                 struct lws *wsi, int m)
418 {
419         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
420
421         WSACloseEvent(pt->events[m + 1]);
422         pt->events[m + 1] = pt->events[pt->fds_count--];
423 }
424
425 LWS_VISIBLE void
426 lws_plat_service_periodic(struct lws_context *context)
427 {
428 }
429
430 LWS_VISIBLE int
431 lws_plat_change_pollfd(struct lws_context *context,
432                       struct lws *wsi, struct lws_pollfd *pfd)
433 {
434         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
435         long networkevents = LWS_POLLHUP;
436
437         if ((pfd->events & LWS_POLLIN))
438                 networkevents |= LWS_POLLIN;
439
440         if ((pfd->events & LWS_POLLOUT))
441                 networkevents |= LWS_POLLOUT;
442
443         if (WSAEventSelect(wsi->sock,
444                         pt->events[wsi->position_in_fds_table + 1],
445                                                networkevents) != SOCKET_ERROR)
446                 return 0;
447
448         lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO);
449
450         return 1;
451 }
452
453 LWS_VISIBLE const char *
454 lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
455 {
456         WCHAR *buffer;
457         DWORD bufferlen = cnt;
458         BOOL ok = FALSE;
459
460         buffer = lws_malloc(bufferlen);
461         if (!buffer) {
462                 lwsl_err("Out of memory\n");
463                 return NULL;
464         }
465
466         if (af == AF_INET) {
467                 struct sockaddr_in srcaddr;
468                 bzero(&srcaddr, sizeof(srcaddr));
469                 srcaddr.sin_family = AF_INET;
470                 memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
471
472                 if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
473                         ok = TRUE;
474 #ifdef LWS_USE_IPV6
475         } else if (af == AF_INET6) {
476                 struct sockaddr_in6 srcaddr;
477                 bzero(&srcaddr, sizeof(srcaddr));
478                 srcaddr.sin6_family = AF_INET6;
479                 memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));
480
481                 if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
482                         ok = TRUE;
483 #endif
484         } else
485                 lwsl_err("Unsupported type\n");
486
487         if (!ok) {
488                 int rv = WSAGetLastError();
489                 lwsl_err("WSAAddressToString() : %d\n", rv);
490         } else {
491                 if (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) <= 0)
492                         ok = FALSE;
493         }
494
495         lws_free(buffer);
496         return ok ? dst : NULL;
497 }
498
499 static lws_filefd_type
500 _lws_plat_file_open(struct lws *wsi, const char *filename,
501                     unsigned long *filelen, int flags)
502 {
503         HANDLE ret;
504         WCHAR buf[MAX_PATH];
505
506         (void)wsi;
507         MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
508         if ((flags & 7) == _O_RDONLY) {
509                 ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
510                           NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
511         } else {
512                 lwsl_err("%s: open for write not implemented\n", __func__);
513                 *filelen = 0;
514                 return LWS_INVALID_FILE;
515         }
516
517         if (ret != LWS_INVALID_FILE)
518                 *filelen = GetFileSize(ret, NULL);
519
520         return ret;
521 }
522
523 static int
524 _lws_plat_file_close(struct lws *wsi, lws_filefd_type fd)
525 {
526         (void)wsi;
527
528         CloseHandle((HANDLE)fd);
529
530         return 0;
531 }
532
533 static unsigned long
534 _lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset)
535 {
536         (void)wsi;
537
538         return SetFilePointer((HANDLE)fd, offset, NULL, FILE_CURRENT);
539 }
540
541 static int
542 _lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
543                     unsigned char* buf, unsigned long len)
544 {
545         DWORD _amount;
546
547         if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &_amount, NULL)) {
548                 *amount = 0;
549
550                 return 1;
551         }
552
553         *amount = (unsigned long)_amount;
554
555         return 0;
556 }
557
558 static int
559 _lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
560                      unsigned char* buf, unsigned long len)
561 {
562         (void)wsi;
563         (void)fd;
564         (void)amount;
565         (void)buf;
566         (void)len;
567
568         lwsl_err("%s: not implemented yet on this platform\n", __func__);
569
570         return -1;
571 }
572
573 LWS_VISIBLE int
574 lws_plat_init(struct lws_context *context,
575               struct lws_context_creation_info *info)
576 {
577         struct lws_context_per_thread *pt = &context->pt[0];
578         int i, n = context->count_threads;
579
580         for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
581                 context->fd_hashtable[i].wsi =
582                         lws_zalloc(sizeof(struct lws*) * context->max_fds);
583
584                 if (!context->fd_hashtable[i].wsi)
585                         return -1;
586         }
587
588         while (n--) {
589                 pt->events = lws_malloc(sizeof(WSAEVENT) *
590                                         (context->fd_limit_per_thread + 1));
591                 if (pt->events == NULL) {
592                         lwsl_err("Unable to allocate events array for %d connections\n",
593                                         context->fd_limit_per_thread + 1);
594                         return 1;
595                 }
596
597                 pt->fds_count = 0;
598                 pt->events[0] = WSACreateEvent();
599
600                 pt++;
601         }
602
603         context->fd_random = 0;
604
605         context->fops.open      = _lws_plat_file_open;
606         context->fops.close     = _lws_plat_file_close;
607         context->fops.seek_cur  = _lws_plat_file_seek_cur;
608         context->fops.read      = _lws_plat_file_read;
609         context->fops.write     = _lws_plat_file_write;
610
611         return 0;
612 }