source: ogServer-Git/src/wol.c

Last change on this file was 216986e, checked in by OpenGnSys Support Team <soporte-og@…>, 2 years ago

#915 consolidate WoL sender function

This patch aims simplifies the WoL sender routine.

A few related changes:

  • Replace goto err to continue if IP address is malformed
  • Use ret |= instead of ret &= to accumulate error code.
  • Property mode set to 100644
File size: 4.4 KB
Line 
1/*
2 * Copyright (C) 2020-2021 Soleta Networks <info@soleta.eu>
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Affero General Public License as published by the
6 * Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 */
9#include <sys/types.h>
10#include <ifaddrs.h>
11#include <string.h>
12#include <netinet/in.h>
13#include <sys/socket.h>
14#include <syslog.h>
15#include <stddef.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <fcntl.h>
21#include "wol.h"
22#include "rest.h"
23#include "cfg.h"
24#include "ogAdmServer.h"
25
26int wol_socket_open(void)
27{
28        unsigned int on = 1;
29        int ret, s;
30
31        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
32        if (s < 0) {
33                syslog(LOG_ERR, "cannot create socket for magic packet\n");
34                return -1;
35        }
36        ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on,
37                         sizeof(on));
38        if (ret < 0) {
39                syslog(LOG_ERR, "cannot set broadcast socket\n");
40                return -1;
41        }
42
43        return s;
44}
45
46static int wake_up_send(int sd, struct sockaddr_in *client,
47                        const struct wol_msg *msg, const struct in_addr *addr)
48{
49        int ret;
50
51        client->sin_addr.s_addr = addr->s_addr;
52
53        ret = sendto(sd, msg, sizeof(*msg), 0,
54                     (struct sockaddr *)client, sizeof(*client));
55        if (ret < 0) {
56                syslog(LOG_ERR, "failed to send wol\n");
57                return -1;
58        }
59
60        return 0;
61}
62
63static int wake_up_broadcast(int sd, struct sockaddr_in *client,
64                             const struct wol_msg *msg)
65{
66        struct sockaddr_in *broadcast_addr, addr = {};
67        struct ifaddrs *ifaddr, *ifa;
68
69        if (getifaddrs(&ifaddr) < 0) {
70                syslog(LOG_ERR, "cannot get list of addresses\n");
71                return -1;
72        }
73
74        addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
75
76        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
77                if (ifa->ifa_addr == NULL ||
78                    ifa->ifa_addr->sa_family != AF_INET ||
79                    strcmp(ifa->ifa_name, ogconfig.wol.interface) != 0)
80                        continue;
81
82                broadcast_addr =
83                        (struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr;
84                addr.sin_addr.s_addr = broadcast_addr->sin_addr.s_addr;
85                break;
86        }
87        freeifaddrs(ifaddr);
88
89        return wake_up_send(sd, client, msg, &addr.sin_addr);
90}
91
92enum wol_delivery_type {
93        OG_WOL_BROADCAST = 1,
94        OG_WOL_UNICAST = 2
95};
96
97int wake_up(int s, const struct in_addr *addr, const struct in_addr *netmask,
98            const char *mac, uint32_t wol_delivery_type)
99{
100        uint32_t mac_addr_u32[OG_WOL_MACADDR_LEN];
101        uint8_t mac_addr[OG_WOL_MACADDR_LEN];
102        struct sockaddr_in dest = {
103                .sin_family = AF_INET,
104                .sin_port = htons(OG_WOL_PORT),
105        };
106        struct in_addr broadcast_addr;
107        struct wol_msg msg = {};
108        int ret, i;
109
110        memset(msg.wol_sequence_ff, 0xff, OG_WOL_SEQUENCE);
111        sscanf(mac, "%02x%02x%02x%02x%02x%02x",
112               &mac_addr_u32[0], &mac_addr_u32[1], &mac_addr_u32[2],
113               &mac_addr_u32[3], &mac_addr_u32[4], &mac_addr_u32[5]);
114
115        for (i = 0; i < OG_WOL_MACADDR_LEN; i++)
116                mac_addr[i] = mac_addr_u32[i];
117        for (i = 0; i < OG_WOL_REPEAT; i++)
118                memcpy(&msg.mac_addr[i][0], mac_addr, OG_WOL_MACADDR_LEN);
119
120        switch (wol_delivery_type) {
121        case OG_WOL_BROADCAST:
122                ret = wake_up_broadcast(s, &dest, &msg);
123                broadcast_addr.s_addr = addr->s_addr | ~netmask->s_addr;
124                ret |= wake_up_send(s, &dest, &msg, &broadcast_addr);
125                break;
126        case OG_WOL_UNICAST:
127                ret = wake_up_send(s, &dest, &msg, addr);
128                break;
129        default:
130                syslog(LOG_ERR, "unknown wol type\n");
131                ret = -1;
132                break;
133        }
134
135        return ret;
136}
137
138#define OG_WOL_CLIENT_TIMEOUT   60.
139
140static void og_client_wol_timer_cb(struct ev_loop *loop, ev_timer *timer,
141                                   int events)
142{
143        struct og_client_wol *cli_wol;
144
145        cli_wol = container_of(timer, struct og_client_wol, timer);
146
147        syslog(LOG_ERR, "timeout WakeOnLAN request for client %s\n",
148               inet_ntoa(cli_wol->addr));
149        og_client_wol_destroy(cli_wol);
150}
151
152struct og_client_wol *og_client_wol_create(const struct in_addr *addr)
153{
154        struct og_client_wol *cli_wol;
155
156        cli_wol = calloc(1, sizeof(struct og_client_wol));
157        if (!cli_wol)
158                return NULL;
159
160        cli_wol->addr = *addr;
161
162        ev_init(&cli_wol->timer, og_client_wol_timer_cb);
163        cli_wol->timer.repeat = OG_WOL_CLIENT_TIMEOUT;
164        ev_timer_again(og_loop, &cli_wol->timer);
165
166        return cli_wol;
167}
168
169void og_client_wol_refresh(struct og_client_wol *cli_wol)
170{
171        ev_timer_again(og_loop, &cli_wol->timer);
172}
173
174void og_client_wol_destroy(struct og_client_wol *cli_wol)
175{
176        ev_timer_stop(og_loop, &cli_wol->timer);
177        list_del(&cli_wol->list);
178        free(cli_wol);
179}
180
181const char *og_client_wol_status(const struct og_client_wol *wol)
182{
183        return "WOL_SENT";
184}
Note: See TracBrowser for help on using the repository browser.