Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
67c47e40
Commit
67c47e40
authored
May 06, 2014
by
Erich E. Hoover
Committed by
Alexandre Julliard
Feb 10, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: Implement the interface change notification object.
parent
b121f27b
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
199 additions
and
3 deletions
+199
-3
sock.c
server/sock.c
+199
-3
No files found.
server/sock.c
View file @
67c47e40
...
...
@@ -46,6 +46,10 @@
#endif
#include <time.h>
#include <unistd.h>
#include <limits.h>
#ifdef HAVE_LINUX_RTNETLINK_H
# include <linux/rtnetlink.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
...
...
@@ -979,16 +983,208 @@ static int sock_add_ifchange( struct sock *sock, const async_data_t *async_data
return
1
;
}
/* stub ifchange object */
static
struct
object
*
get_ifchange
(
void
)
#ifdef HAVE_LINUX_RTNETLINK_H
/* only keep one ifchange object around, all sockets waiting for wakeups will look to it */
static
struct
object
*
ifchange_object
;
static
void
ifchange_dump
(
struct
object
*
obj
,
int
verbose
);
static
struct
fd
*
ifchange_get_fd
(
struct
object
*
obj
);
static
void
ifchange_destroy
(
struct
object
*
obj
);
static
int
ifchange_get_poll_events
(
struct
fd
*
fd
);
static
void
ifchange_poll_event
(
struct
fd
*
fd
,
int
event
);
static
void
ifchange_reselect_async
(
struct
fd
*
fd
,
struct
async_queue
*
queue
);
struct
ifchange
{
struct
object
obj
;
/* object header */
struct
fd
*
fd
;
/* interface change file descriptor */
struct
list
sockets
;
/* list of sockets to send interface change notifications */
};
static
const
struct
object_ops
ifchange_ops
=
{
sizeof
(
struct
ifchange
),
/* size */
ifchange_dump
,
/* dump */
no_get_type
,
/* get_type */
add_queue
,
/* add_queue */
NULL
,
/* remove_queue */
NULL
,
/* signaled */
no_satisfied
,
/* satisfied */
no_signal
,
/* signal */
ifchange_get_fd
,
/* get_fd */
default_fd_map_access
,
/* map_access */
default_get_sd
,
/* get_sd */
default_set_sd
,
/* set_sd */
no_lookup_name
,
/* lookup_name */
no_open_file
,
/* open_file */
no_close_handle
,
/* close_handle */
ifchange_destroy
/* destroy */
};
static
const
struct
fd_ops
ifchange_fd_ops
=
{
ifchange_get_poll_events
,
/* get_poll_events */
ifchange_poll_event
,
/* poll_event */
NULL
,
/* flush */
NULL
,
/* get_fd_type */
NULL
,
/* ioctl */
NULL
,
/* queue_async */
ifchange_reselect_async
,
/* reselect_async */
NULL
/* cancel_async */
};
static
void
ifchange_dump
(
struct
object
*
obj
,
int
verbose
)
{
assert
(
obj
->
ops
==
&
ifchange_ops
);
fprintf
(
stderr
,
"Interface change
\n
"
);
}
static
struct
fd
*
ifchange_get_fd
(
struct
object
*
obj
)
{
struct
ifchange
*
ifchange
=
(
struct
ifchange
*
)
obj
;
return
(
struct
fd
*
)
grab_object
(
ifchange
->
fd
);
}
static
void
ifchange_destroy
(
struct
object
*
obj
)
{
struct
ifchange
*
ifchange
=
(
struct
ifchange
*
)
obj
;
assert
(
obj
->
ops
==
&
ifchange_ops
);
release_object
(
ifchange
->
fd
);
/* reset the global ifchange object so that it will be recreated if it is needed again */
assert
(
obj
==
ifchange_object
);
ifchange_object
=
NULL
;
}
static
int
ifchange_get_poll_events
(
struct
fd
*
fd
)
{
return
POLLIN
;
}
/* wake up all the sockets waiting for a change notification event */
static
void
ifchange_wake_up
(
struct
object
*
obj
,
unsigned
int
status
)
{
struct
ifchange
*
ifchange
=
(
struct
ifchange
*
)
obj
;
struct
list
*
ptr
,
*
next
;
assert
(
obj
->
ops
==
&
ifchange_ops
);
assert
(
obj
==
ifchange_object
);
LIST_FOR_EACH_SAFE
(
ptr
,
next
,
&
ifchange
->
sockets
)
{
struct
sock
*
sock
=
LIST_ENTRY
(
ptr
,
struct
sock
,
ifchange_entry
);
assert
(
sock
->
ifchange_q
);
async_wake_up
(
sock
->
ifchange_q
,
status
);
/* issue ifchange notification for the socket */
sock_destroy_ifchange_q
(
sock
);
/* remove socket from list and decrement ifchange refcount */
}
}
static
void
ifchange_poll_event
(
struct
fd
*
fd
,
int
event
)
{
struct
object
*
ifchange
=
get_fd_user
(
fd
);
unsigned
int
status
=
STATUS_PENDING
;
char
buffer
[
PIPE_BUF
];
int
r
;
r
=
recv
(
get_unix_fd
(
fd
),
buffer
,
sizeof
(
buffer
),
MSG_DONTWAIT
);
if
(
r
<
0
)
{
if
(
errno
==
EWOULDBLOCK
||
errno
==
EAGAIN
)
return
;
/* retry when poll() says the socket is ready */
status
=
sock_get_ntstatus
(
errno
);
}
else
if
(
r
>
0
)
{
struct
nlmsghdr
*
nlh
;
for
(
nlh
=
(
struct
nlmsghdr
*
)
buffer
;
NLMSG_OK
(
nlh
,
r
);
nlh
=
NLMSG_NEXT
(
nlh
,
r
))
{
if
(
nlh
->
nlmsg_type
==
NLMSG_DONE
)
break
;
if
(
nlh
->
nlmsg_type
==
RTM_NEWADDR
||
nlh
->
nlmsg_type
==
RTM_DELADDR
)
status
=
STATUS_SUCCESS
;
}
}
else
status
=
STATUS_CANCELLED
;
if
(
status
!=
STATUS_PENDING
)
ifchange_wake_up
(
ifchange
,
status
);
}
static
void
ifchange_reselect_async
(
struct
fd
*
fd
,
struct
async_queue
*
queue
)
{
/* do nothing, this object is about to disappear */
}
#endif
/* we only need one of these interface notification objects, all of the sockets dependent upon
* it will wake up when a notification event occurs */
static
struct
object
*
get_ifchange
(
void
)
{
#ifdef HAVE_LINUX_RTNETLINK_H
struct
ifchange
*
ifchange
;
struct
sockaddr_nl
addr
;
int
unix_fd
;
if
(
ifchange_object
)
{
/* increment the refcount for each socket that uses the ifchange object */
return
grab_object
(
ifchange_object
);
}
/* create the socket we need for processing interface change notifications */
unix_fd
=
socket
(
PF_NETLINK
,
SOCK_RAW
,
NETLINK_ROUTE
);
if
(
unix_fd
==
-
1
)
{
sock_set_error
();
return
NULL
;
}
fcntl
(
unix_fd
,
F_SETFL
,
O_NONBLOCK
);
/* make socket nonblocking */
memset
(
&
addr
,
0
,
sizeof
(
addr
)
);
addr
.
nl_family
=
AF_NETLINK
;
addr
.
nl_groups
=
RTMGRP_IPV4_IFADDR
;
/* bind the socket to the special netlink kernel interface */
if
(
bind
(
unix_fd
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
)
)
==
-
1
)
{
close
(
unix_fd
);
sock_set_error
();
return
NULL
;
}
if
(
!
(
ifchange
=
alloc_object
(
&
ifchange_ops
)))
{
close
(
unix_fd
);
set_error
(
STATUS_NO_MEMORY
);
return
NULL
;
}
list_init
(
&
ifchange
->
sockets
);
if
(
!
(
ifchange
->
fd
=
create_anonymous_fd
(
&
ifchange_fd_ops
,
unix_fd
,
&
ifchange
->
obj
,
0
)))
{
release_object
(
ifchange
);
set_error
(
STATUS_NO_MEMORY
);
return
NULL
;
}
set_fd_events
(
ifchange
->
fd
,
POLLIN
);
/* enable read wakeup on the file descriptor */
/* the ifchange object is now successfully configured */
ifchange_object
=
&
ifchange
->
obj
;
return
&
ifchange
->
obj
;
#else
set_error
(
STATUS_NOT_SUPPORTED
);
return
NULL
;
#endif
}
/*
stub ifchange add socket to
list */
/*
add the socket to the interface change notification
list */
static
void
ifchange_add_sock
(
struct
object
*
obj
,
struct
sock
*
sock
)
{
#ifdef HAVE_LINUX_RTNETLINK_H
struct
ifchange
*
ifchange
=
(
struct
ifchange
*
)
obj
;
list_add_tail
(
&
ifchange
->
sockets
,
&
sock
->
ifchange_entry
);
#endif
}
/* create a new ifchange queue for a specific socket or, if one already exists, reuse the existing one */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment