update comments on all ifdefs
[olsrd.git] / lib / dyn_gw / src / olsrd_dyn_gw.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /*
43  * -Threaded ping code added by Jens Nachtigall
44  * -HNA4 checking by bjoern riemer
45  */
46
47 #include <arpa/inet.h>
48
49 #include "olsr_types.h"
50 #include "olsrd_dyn_gw.h"
51 #include "olsr.h"
52 #include "defs.h"
53 #include "ipcalc.h"
54 #include "scheduler.h"
55 #include "log.h"
56 #include "routing_table.h"
57
58 #include <stdio.h>
59 #include <string.h>
60 #include <stdlib.h>
61 #include <sys/time.h>
62 #include <net/route.h>
63 #ifdef __linux__
64 #include <linux/in_route.h>
65 #endif /* __linux__ */
66 #include <unistd.h>
67 #include <errno.h>
68 #include <time.h>
69 #ifndef _WIN32
70 #include <pthread.h>
71 #else /* _WIN32 */
72 #define WIN32_LEAN_AND_MEAN
73 #include <windows.h>
74 #undef interface
75
76 #define close(x) closesocket(x)
77
78 typedef HANDLE pthread_mutex_t;
79 typedef HANDLE pthread_t;
80
81 int pthread_create(HANDLE * Hand, void *Attr, void *(*Func) (void *), void *Arg);
82 int pthread_kill(HANDLE Hand, int Sig);
83 int pthread_mutex_init(HANDLE * Hand, void *Attr);
84 int pthread_mutex_lock(HANDLE * Hand);
85 int pthread_mutex_unlock(HANDLE * Hand);
86
87 struct ThreadPara {
88   void *(*Func) (void *);
89   void *Arg;
90 };
91 #endif /* _WIN32 */
92
93 static int hna_check_interval   = DEFAULT_HNA_CHECK_INTERVAL;
94 /* set default interval, in case none is given in the config file */
95 static int ping_check_interval = DEFAULT_PING_CHECK_INTERVAL;
96
97 /* list to store the Ping IP addresses given in the config file */
98 struct ping_list {
99   char *ping_address;
100   struct ping_list *next;
101 };
102
103 static struct ping_list *add_to_ping_list(const char *, struct ping_list *);
104
105 struct hna_list {
106   union olsr_ip_addr   hna_addr;
107   uint8_t              hna_prefixlen;
108   bool                 hna_added;
109   bool                 checked;
110   bool                 active;
111   struct hna_list *    next;
112 };
113
114 static struct hna_list *add_to_hna_list(struct hna_list *, union olsr_ip_addr *hna_addr, uint8_t hna_prefixlen);
115
116 struct hna_group {
117   struct hna_list *    hna_list;
118   struct ping_list *   ping_hosts;
119   bool                 probe_ok;
120   struct hna_group *   next;
121 };
122
123 bool hna_ping_check     = false;
124 static struct hna_group * hna_groups = NULL;
125
126 static struct hna_group *add_to_hna_group(struct hna_group *);
127
128 static void looped_checks(void *) __attribute__ ((noreturn));
129
130 static bool check_gw(union olsr_ip_addr *, uint8_t, struct ping_list *);
131
132 static int ping_is_possible(struct ping_list *);
133
134 /* Event function to register with the scheduler */
135 static void olsr_event_doing_hna(void *);
136
137 struct hna_list* find_hna(uint32_t src_addr, uint32_t src_mask);
138
139 char *get_ip_str(uint32_t address, char *s, size_t maxlen);
140 int update_routing(void);
141
142 /**
143  * read config file parameters
144  */
145 static int
146 set_plugin_ping(const char *value, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
147 {
148   union olsr_ip_addr foo_addr;
149
150   if (inet_pton(olsr_cnf->ip_version, value, &foo_addr) <= 0) {
151     OLSR_PRINTF(0, "Illegal IP address \"%s\"", value);
152     return 1;
153   }
154
155   if (hna_groups == NULL) { 
156     hna_groups = add_to_hna_group(hna_groups);
157     if (hna_groups == NULL)
158       return 1;
159   } else {
160     if (hna_groups->hna_list != NULL) {
161       hna_groups = add_to_hna_group(hna_groups);
162     }
163   }
164
165   hna_groups->ping_hosts = add_to_ping_list(value, hna_groups->ping_hosts);
166   hna_ping_check = true;
167   
168   return 0;
169 }
170
171 static int
172 set_plugin_hna(const char *value, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
173 {
174   union olsr_ip_addr temp_addr;
175   union olsr_ip_addr temp_mask;
176   char s_addr[128];
177   char s_mask[128];
178   
179   //Example: 192.168.1.0  255.255.255.0
180   int i = sscanf(value, "%127s %127s", s_addr, s_mask);
181   if (i != 2) {
182     OLSR_PRINTF(0, "Cannot get IP address and netmask from \"%s\"", value);
183     return 1;
184   }
185
186   if (inet_pton(olsr_cnf->ip_version, s_addr, &temp_addr) <= 0) {
187     OLSR_PRINTF(0, "Illegal IP address \"%s\"", s_addr);
188     return 1;
189   }
190
191   if (inet_pton(olsr_cnf->ip_version, s_mask, &temp_mask) <= 0) {
192     OLSR_PRINTF(0, "Illegal netmask \"%s\"", s_mask);
193     return 1;
194   }
195
196   if (hna_groups == NULL)
197   {
198     hna_groups = add_to_hna_group(hna_groups);
199     if (hna_groups == NULL) {
200       return 1;
201     }
202   }
203         
204   hna_groups->hna_list = add_to_hna_list(hna_groups->hna_list, &temp_addr, olsr_netmask_to_prefix(&temp_mask));
205   if (hna_groups->hna_list == NULL) {
206     return 1;
207   }
208   return 0;
209 }
210
211 static const struct olsrd_plugin_parameters plugin_parameters[] = {
212   {.name = "interval",      .set_plugin_parameter = &set_plugin_int,  .data = &ping_check_interval  },
213   {.name = "pinginterval",  .set_plugin_parameter = &set_plugin_int,  .data = &ping_check_interval  },
214   {.name = "checkinterval", .set_plugin_parameter = &set_plugin_int,  .data = &hna_check_interval   },
215   {.name = "ping",          .set_plugin_parameter = &set_plugin_ping, .data = NULL                  },
216   {.name = "hna",           .set_plugin_parameter = &set_plugin_hna,  .data = NULL                  },
217 };
218
219 void
220 olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
221 {
222   *params = plugin_parameters;
223   *size = sizeof(plugin_parameters) / sizeof(*plugin_parameters);
224 }
225
226 /**
227  *Do initialization here
228  *
229  *
230  *This function is called by the my_init
231  *function in uolsrd_plugin.c
232  *It is ran _after_ register_olsr_param
233  */
234 int
235 olsrd_plugin_init(void)
236 {
237   pthread_t ping_thread;
238
239   if (hna_groups == NULL) {
240     hna_groups = add_to_hna_group(hna_groups);
241     if (hna_groups == NULL)
242       return 1;
243   }
244         
245   // Add a default gateway if the top entry was just a ping address
246   if (hna_groups->hna_list == NULL) {
247     union olsr_ip_addr temp_addr;
248     union olsr_ip_addr temp_mask;
249     
250     temp_addr.v4.s_addr = INET_ADDR;
251     temp_mask.v4.s_addr = INET_MASK;
252     hna_groups->hna_list = add_to_hna_list(hna_groups->hna_list, &temp_addr, olsr_netmask_to_prefix(&temp_mask));
253     if (hna_groups->hna_list == NULL) {
254       return 1;
255     }
256   }
257         
258   // Prepare all routing information
259   update_routing();
260   
261   if (hna_ping_check) {
262     pthread_create(&ping_thread, NULL, (void *(*)(void *))looped_checks, NULL);
263   } else {
264     struct hna_group *grp;
265     for (grp = hna_groups; grp; grp = grp->next) {
266       grp->probe_ok = true;
267     }
268   }
269
270   // Print the current configuration
271   {
272     struct hna_group *grp;
273     int i = 0;
274     for (grp = hna_groups; grp; grp = grp->next, ++i) {
275       struct hna_list *lst;
276       struct ping_list *png;
277             
278       olsr_printf(1, "Group %d:\n", i);
279       for (lst = grp->hna_list; lst; lst = lst->next) {
280         char addr[INET_ADDRSTRLEN];
281         olsr_printf(1, "  HNA %s\n", get_ip_str(lst->hna_addr.v4.s_addr, addr, INET_ADDRSTRLEN));
282       }
283       for (png = grp->ping_hosts; png; png = png->next) {
284         olsr_printf(1, "  PING %s\n", png->ping_address);
285       }
286     }
287   }
288
289   /* Register the GW check */
290   olsr_start_timer(hna_check_interval, 0, OLSR_TIMER_PERIODIC, &olsr_event_doing_hna, NULL, 0);
291   return 1;
292 }
293
294 /**
295  * Scheduled event to update the hna table,
296  * called from olsrd main thread to keep the hna table thread-safe
297  */
298 static void
299 olsr_event_doing_hna(void *foo __attribute__ ((unused)))
300 {
301   struct hna_group* grp;
302   struct hna_list *li;
303
304   update_routing();
305   
306   for (grp = hna_groups; grp; grp = grp->next) {
307     for (li = grp->hna_list; li; li = li->next) {
308       if (!li->hna_added) {
309         if (grp->probe_ok && li->active) {
310           olsr_printf(1, "Adding OLSR local HNA entry\n");
311           ip_prefix_list_add(&olsr_cnf->hna_entries, &li->hna_addr, li->hna_prefixlen);
312           li->hna_added = true;
313         }
314       } else {
315         if (!grp->probe_ok || !li->active) {
316           while (ip_prefix_list_remove(&olsr_cnf->hna_entries, &li->hna_addr, li->hna_prefixlen)) {
317             olsr_printf(1, "Removing OLSR local HNA entry\n");
318           }
319           li->hna_added = false;
320         }
321       }
322     }
323   }
324 }
325
326 /**
327  * the threaded function which happens within an endless loop,
328  * reiterated every "Interval" sec (as given in the config or
329  * the default value)
330  */
331 static void
332 looped_checks(void *foo __attribute__ ((unused)))
333 {
334   for (;;) {
335     struct hna_group *grp;
336     struct hna_list *li;
337     struct timespec remainder_spec;
338     /* the time to wait in "Interval" sec (see connfig), default=5sec */
339     struct timespec sleeptime_spec = { ping_check_interval, 0L };
340
341     for (grp = hna_groups; grp; grp = grp->next) {
342       for (li = grp->hna_list; li; li = li->next) {
343       
344                 // If this HNA is not active skip to the next one
345         if (!li->active)
346           continue;
347           
348         /* check for gw in table entry and if Ping IPs are given also do pings */
349         grp->probe_ok = check_gw(&li->hna_addr, li->hna_prefixlen, grp->ping_hosts);
350         if (grp->probe_ok)
351           break;        // Valid host found so we can bail out of the inner loop here
352       }
353     }
354
355     while (nanosleep(&sleeptime_spec, &remainder_spec) < 0)
356       sleeptime_spec = remainder_spec;
357   }
358   // return NULL;
359 }
360
361 /* -------------------------------------------------------------------------
362  * Function   : find_hna
363  * Description: Lookup an HNA that matches the specified parameters
364  * Input      : src_addr - IP address of the HNA to find
365  *              src_mask - Address mask of the HNA to find
366  * Output     : none
367  * Return     : The HNA specified or NULL when HNA not found
368  * Data Used  : none
369  * ------------------------------------------------------------------------- */
370 struct hna_list*
371 find_hna(uint32_t src_addr, uint32_t src_mask)
372 {
373   struct hna_group * grp;
374   struct hna_list *li;
375   union olsr_ip_addr mask;
376
377   for (grp = hna_groups; grp; grp = grp->next) {
378     for (li = grp->hna_list; li; li = li->next) {
379       olsr_prefix_to_netmask(&mask, li->hna_prefixlen);
380       if (li->hna_addr.v4.s_addr == src_addr && mask.v4.s_addr == src_mask) {
381         return li;
382       }
383     }
384   }
385   return NULL;
386 }
387
388 /* -------------------------------------------------------------------------
389  * Function   : get_ip_str
390  * Description: Convert the specified address to an IPv4 compatible string
391  * Input      : address - IPv4 address to convert to string 
392  *              s       - string buffer to contain the resulting string
393  *              maxlen  - maximum length of the string buffer 
394  * Output     : none
395  * Return     : Pointer to the string buffer containing the result
396  * Data Used  : none
397  * ------------------------------------------------------------------------- */
398 char *
399 get_ip_str(uint32_t address, char *s, size_t maxlen)
400 {
401   struct sockaddr_in v4;
402   
403   v4.sin_addr.s_addr = address;
404   inet_ntop(AF_INET, &v4.sin_addr, s, maxlen);
405
406   return s;
407 }
408
409 /* -------------------------------------------------------------------------
410  * Function   : update_routing
411  * Description: Mark the HNAs in the HNA list(s) corresponding to the results
412  *              found in the routing table. HNAs that are found in the routing
413  *              table will be marked as 'active', otherwise they'll remain
414  *              inactive.    
415  * Input      : nothing
416  * Output     : none
417  * Return     : -1 if an error occurred, 0 otherwise
418  * Data Used  : none
419  * ------------------------------------------------------------------------- */
420 int 
421 update_routing(void)
422 {
423   char buf[1024], iface[16];
424   uint32_t gate_addr, dest_addr, netmask;
425   unsigned int iflags;
426   int metric, refcnt, use;
427   struct hna_group *grp;
428   struct hna_list *li;
429   
430   FILE *fp = fopen(PROCENTRY_ROUTE, "r");
431   if (!fp) {
432     perror(PROCENTRY_ROUTE);
433     olsr_printf(1, "INET (IPv4) not configured in this system.\n");
434     return -1;
435   }
436
437   // Phase 1: reset the 'checked' flag, during the check of the routing table we 
438   // will (re)discover whether the HNA is valid or not.
439   for (grp = hna_groups; grp; grp = grp->next) {
440     for (li = grp->hna_list; li; li = li->next) {
441       li->checked = false;
442     }
443   }
444
445   /*
446      olsr_printf(1, "Genmask         Destination     Gateway         "
447      "Flags Metric Ref    Use Iface\n");
448    */
449   while (fgets(buf, sizeof(buf), fp)) {
450     struct hna_list *hna;
451     char s_addr[INET_ADDRSTRLEN], s_mask[INET_ADDRSTRLEN];
452     
453     int num = sscanf(buf, 
454                      "%15s %128X %128X %X %d %d %d %128X \n",
455                      iface, 
456                      &dest_addr,
457                      &gate_addr,
458                      &iflags, 
459                      &refcnt,
460                      &use,
461                      &metric,
462                      &netmask);
463     if (num < 8)
464       continue;
465
466     get_ip_str(dest_addr, s_addr, INET_ADDRSTRLEN);
467     get_ip_str(netmask, s_mask, INET_ADDRSTRLEN);
468     
469     hna = find_hna(dest_addr, netmask);
470     if (hna == NULL) {  // Entry not found, try the next one
471       continue;
472     }
473     
474     if ((iflags & RTF_UP) && (metric != RT_METRIC_DEFAULT)) {
475       hna->checked = true;
476     }
477   }
478   fclose(fp);
479   
480   // Phase 2: now copy the 'checked' flag to the 'active' flag.
481   // The total check is a 2-phase process so the ping check loop won't be 
482   // disturbed too badly.
483   for (grp = hna_groups; grp; grp = grp->next) {
484     for (li = grp->hna_list; li; li = li->next) {
485       li->active = li->checked;
486     }
487   }
488         
489   return 0;
490 }
491
492 /* -------------------------------------------------------------------------
493  * Function   : check_gw
494  * Description: Check the specified gateway(s) by sending a ping
495  * Input      : addr      - the address of the HNA to which the ping is related
496  *              prefixlen - the length of the prefix for this HNA 
497  *              the_ping_list - list with related ping hosts
498  * Output     : none
499  * Return     : true if the ping host could be reached, false otherwise
500  * Data Used  : none
501  * ------------------------------------------------------------------------- */
502 static bool
503 check_gw(union olsr_ip_addr *addr, uint8_t prefixlen, struct ping_list *the_ping_list)
504 {
505   bool retval = false;
506   union olsr_ip_addr mask;
507
508   olsr_prefix_to_netmask(&mask, prefixlen);
509   
510   /* don't ping, if there was no "Ping" IP addr in the config file */
511   if (the_ping_list != NULL) {
512     /*validate the found inet gw by pinging */
513     if (ping_is_possible(the_ping_list)) {
514       olsr_printf(1, "HNA[%08x/%08x](ping is possible) detected in routing table.\n", addr->v4.s_addr, mask.v4.s_addr);
515       retval = true;
516     }
517   } else {
518     olsr_printf(1, "HNA[%08x/%08x] detected in routing table.\n", addr->v4.s_addr, mask.v4.s_addr);
519     retval = true;
520   }
521
522   if (retval == false) {
523     /* And we cast here since we get warnings on Win32 */
524     olsr_printf(1, "HNA[%08x/%08x] is invalid\n", (unsigned int)addr->v4.s_addr, (unsigned int)mask.v4.s_addr);
525   }
526   return retval;
527 }
528
529 /* -------------------------------------------------------------------------
530  * Function   : ping_is_possible
531  * Description: Ping the specified host(s)
532  * Input      : the_ping_list - the list of hosts to ping
533  * Output     : none
534  * Return     : 1 if any host responded, 0 otherwise
535  * Data Used  : none
536  * ------------------------------------------------------------------------- */
537 static int
538 ping_is_possible(struct ping_list *the_ping_list)
539 {
540   struct ping_list *list;
541   for (list = the_ping_list; list; list = list->next) {
542     char ping_command[50];
543     snprintf(ping_command, sizeof(ping_command), "ping -c 1 -q %s", list->ping_address);
544     olsr_printf(1, "\nDo ping on %s ...\n", list->ping_address);
545     if (system(ping_command) == 0) {
546       olsr_printf(1, "...OK\n\n");
547       return 1;
548     }
549     olsr_printf(1, "...FAILED\n\n");
550   }
551   return 0;
552 }
553
554 /* -------------------------------------------------------------------------
555  * Function   : add_to_ping_list
556  * Description: Add a new ping host to the list of ping hosts
557  * Input      : ping_address - the address of the ping host
558  *              the_ping_list - the list of ping hosts 
559  * Output     : none
560  * Return     : a pointer to the newly added ping host, i.e. start of the list
561  * Data Used  : none
562  * ------------------------------------------------------------------------- */
563 /* add the valid IPs to the head of the list */
564 static struct ping_list *
565 add_to_ping_list(const char *ping_address, struct ping_list *the_ping_list)
566 {
567   struct ping_list *new = calloc(1, sizeof(struct ping_list));
568   if (!new) {
569     fprintf(stderr, "DYN GW: Out of memory!\n");
570     olsr_syslog(OLSR_LOG_ERR, "DYN GW: Out of memory!\n");
571     exit(0);
572   }
573   new->ping_address = strdup(ping_address);
574   new->next = the_ping_list;
575   return new;
576 }
577
578 /* -------------------------------------------------------------------------
579  * Function   : add_to_hna_list
580  * Description: Add a new HNA entry to the list of HNA entries
581  * Input      : list_root - the start of the list with HNA entries
582  *              hna_addr  - the address of the new HNA entry
583  *              prefixlen - the prefix-length of the new HNA entry 
584  * Output     : none
585  * Return     : a pointer to the newly added HNA entry, i.e. start of the list
586  * Data Used  : none
587  * ------------------------------------------------------------------------- */
588 static struct hna_list *
589 add_to_hna_list(struct hna_list *list_root, union olsr_ip_addr *hna_addr, uint8_t hna_prefixlen)
590 {
591   struct hna_list *new = calloc(1, sizeof(struct hna_list));
592   if (new == NULL) {
593     fprintf(stderr, "DYN GW: Out of memory!\n");
594     olsr_syslog(OLSR_LOG_ERR, "DYN GW: Out of memory!\n");
595     exit(0);
596   }
597
598   new->hna_addr.v4 = hna_addr->v4;
599   new->hna_prefixlen = hna_prefixlen;
600   new->hna_added = false;
601   new->next = list_root;
602   return new;
603 }
604
605 /* -------------------------------------------------------------------------
606  * Function   : add_to_hna_group
607  * Description: Add a new HNA group to the list of HNA groups
608  * Input      : list_root - the start of the list with HNA groups
609  * Output     : none
610  * Return     : a pointer to the newly added HNA group, i.e. start of the list
611  * Data Used  : none
612  * ------------------------------------------------------------------------- */
613 static struct hna_group *
614 add_to_hna_group(struct hna_group *list_root)
615 {
616   struct hna_group *new = calloc(1, sizeof(struct hna_group));
617   if (new == NULL) {
618     fprintf(stderr, "DYN GW: Out of memory!\n");
619     olsr_syslog(OLSR_LOG_ERR, "DYN GW: Out of memory!\n");
620     exit(0);
621   }
622         
623   new->next =  list_root;
624   return new;
625 }
626
627
628 #ifdef _WIN32
629
630 /*
631  * Windows pthread compat stuff
632  */
633 static unsigned long __stdcall
634 ThreadWrapper(void *Para)
635 {
636   struct ThreadPara *Cast;
637   void *(*Func) (void *);
638   void *Arg;
639
640   Cast = (struct ThreadPara *)Para;
641
642   Func = Cast->Func;
643   Arg = Cast->Arg;
644
645   HeapFree(GetProcessHeap(), 0, Para);
646
647   Func(Arg);
648
649   return 0;
650 }
651
652 int
653 pthread_create(HANDLE * Hand, void *Attr __attribute__ ((unused)), void *(*Func) (void *), void *Arg)
654 {
655   struct ThreadPara *Para;
656   unsigned long ThreadId;
657
658   Para = HeapAlloc(GetProcessHeap(), 0, sizeof(struct ThreadPara));
659
660   if (Para == NULL)
661     return -1;
662
663   Para->Func = Func;
664   Para->Arg = Arg;
665
666   *Hand = CreateThread(NULL, 0, ThreadWrapper, Para, 0, &ThreadId);
667
668   if (*Hand == NULL)
669     return -1;
670
671   return 0;
672 }
673
674 int
675 pthread_kill(HANDLE Hand, int Sig __attribute__ ((unused)))
676 {
677   if (!TerminateThread(Hand, 0))
678     return -1;
679
680   return 0;
681 }
682
683 int
684 pthread_mutex_init(HANDLE * Hand, void *Attr __attribute__ ((unused)))
685 {
686   *Hand = CreateMutex(NULL, FALSE, NULL);
687
688   if (*Hand == NULL)
689     return -1;
690
691   return 0;
692 }
693
694 int
695 pthread_mutex_lock(HANDLE * Hand)
696 {
697   if (WaitForSingleObject(*Hand, INFINITE) == WAIT_FAILED)
698     return -1;
699
700   return 0;
701 }
702
703 int
704 pthread_mutex_unlock(HANDLE * Hand)
705 {
706   if (!ReleaseMutex(*Hand))
707     return -1;
708
709   return 0;
710 }
711
712 #endif /* _WIN32 */
713
714 /*
715  * Local Variables:
716  * c-basic-offset: 2
717  * indent-tabs-mode: nil
718  * End:
719  */