summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--device.c56
-rw-r--r--device.h29
-rw-r--r--log.c18
-rw-r--r--log.h14
-rw-r--r--main.c66
-rw-r--r--usb-linux.c251
-rw-r--r--usb.h18
-rw-r--r--utils.c6
-rw-r--r--utils.h16
10 files changed, 440 insertions, 36 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 81a6965..acbc779 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,6 @@ set(LIBS ${LIBS} ${USB_LIBRARIES})
11#set(CMAKE_VERBOSE_MAKEFILE ON) 11#set(CMAKE_VERBOSE_MAKEFILE ON)
12 12
13add_definitions(-Wall -O2) 13add_definitions(-Wall -O2)
14add_executable(usbmuxd main.c usb-linux.c log.c utils.c) 14add_executable(usbmuxd main.c usb-linux.c log.c utils.c device.c)
15target_link_libraries(usbmuxd ${LIBS}) 15target_link_libraries(usbmuxd ${LIBS})
16 16
diff --git a/device.c b/device.c
new file mode 100644
index 0000000..659f4ae
--- /dev/null
+++ b/device.c
@@ -0,0 +1,56 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 or version 3.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19*/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <stdlib.h>
26#include "device.h"
27#include "usb.h"
28#include "log.h"
29
30int device_id;
31/*
32int get_next_device_id(void)
33{
34 int i;
35 while(1) {
36 for(i=0; i<num_devs; i++) {
37 if(device_list[i].dev && device_list[i].id == device_id) {
38 device_id++;
39 break;
40 }
41 }
42 if(i < num_devs)
43 break;
44 }
45 return device_id++;
46}
47*/
48void device_add(struct usb_device *dev)
49{
50 usbmuxd_log(LL_NOTICE, "Connected to new device on location 0x%x with serial number %s", usb_get_location(dev), usb_get_serial(dev));
51}
52
53void device_remove(struct usb_device *dev)
54{
55 usbmuxd_log(LL_NOTICE, "Removed device on location 0x%x with serial number %s", usb_get_location(dev), usb_get_serial(dev));
56}
diff --git a/device.h b/device.h
new file mode 100644
index 0000000..11beaea
--- /dev/null
+++ b/device.h
@@ -0,0 +1,29 @@
1/*
2 usbmuxd - iPhone/iPod Touch USB multiplex server daemon
3
4Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 or version 3.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19*/
20
21#ifndef __DEVICE_H__
22#define __DEVICE_H__
23
24#include "usb.h"
25
26void device_add(struct usb_device *dev);
27void device_remove(struct usb_device *dev);
28
29#endif
diff --git a/log.c b/log.c
index d7f57df..29b3506 100644
--- a/log.c
+++ b/log.c
@@ -26,25 +26,33 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26#include <stdlib.h> 26#include <stdlib.h>
27#include <string.h> 27#include <string.h>
28#include <stdarg.h> 28#include <stdarg.h>
29#include <time.h>
30#include <sys/time.h>
29 31
30#include "log.h" 32#include "log.h"
31 33
32int log_level = LOG_SPEW; 34int log_level = LL_SPEW;
33 35
34void usbmuxd_log(enum loglevel level, const char *fmt, ...) 36void usbmuxd_log(enum loglevel level, const char *fmt, ...)
35{ 37{
36 va_list ap; 38 va_list ap;
37 char *fs; 39 char *fs;
40 struct timeval ts;
41 struct tm *tp;
38 42
39 if(level < log_level) 43 gettimeofday(&ts, NULL);
44 tp = localtime(&ts.tv_sec);
45
46 if(level > log_level)
40 return; 47 return;
41 48
42 fs = malloc(10 + strlen(fmt)); 49 fs = malloc(20 + strlen(fmt));
43 sprintf(fs, "[%d] %s\n", level, fmt); 50 strftime(fs, 10, "[%H:%M:%S", tp);
51 sprintf(fs+9, ".%03d][%d] %s\n", (int)(ts.tv_usec / 1000), level, fmt);
44 52
45 va_start(ap, fmt); 53 va_start(ap, fmt);
46 vfprintf(stderr, fs, ap); 54 vfprintf(stderr, fs, ap);
47 va_end(ap); 55 va_end(ap);
48 56
49 free(fs); 57 free(fs);
50} \ No newline at end of file 58}
diff --git a/log.h b/log.h
index fda2e1a..56ecbf4 100644
--- a/log.h
+++ b/log.h
@@ -22,13 +22,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22#define __LOG_H__ 22#define __LOG_H__
23 23
24enum loglevel { 24enum loglevel {
25 LOG_SPEW = 0, 25 LL_FATAL = 0,
26 LOG_DEBUG, 26 LL_ERROR,
27 LOG_INFO, 27 LL_WARNING,
28 LOG_NOTICE, 28 LL_NOTICE,
29 LOG_WARNING, 29 LL_INFO,
30 LOG_ERROR, 30 LL_DEBUG,
31 LOG_FATAL, 31 LL_SPEW,
32}; 32};
33 33
34extern int log_level; 34extern int log_level;
diff --git a/main.c b/main.c
index c2467a2..6773d0e 100644
--- a/main.c
+++ b/main.c
@@ -42,13 +42,13 @@ int create_socket(void) {
42 int listenfd; 42 int listenfd;
43 43
44 if(unlink(socket_path) == -1 && errno != ENOENT) { 44 if(unlink(socket_path) == -1 && errno != ENOENT) {
45 usbmuxd_log(LOG_FATAL, "unlink(%s) failed: %s", socket_path, strerror(errno)); 45 usbmuxd_log(LL_FATAL, "unlink(%s) failed: %s", socket_path, strerror(errno));
46 return -1; 46 return -1;
47 } 47 }
48 48
49 listenfd = socket(AF_UNIX, SOCK_STREAM, 0); 49 listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
50 if (listenfd == -1) { 50 if (listenfd == -1) {
51 usbmuxd_log(LOG_FATAL, "socket() failed: %s", strerror(errno)); 51 usbmuxd_log(LL_FATAL, "socket() failed: %s", strerror(errno));
52 return -1; 52 return -1;
53 } 53 }
54 54
@@ -56,37 +56,85 @@ int create_socket(void) {
56 bind_addr.sun_family = AF_UNIX; 56 bind_addr.sun_family = AF_UNIX;
57 strcpy(bind_addr.sun_path, socket_path); 57 strcpy(bind_addr.sun_path, socket_path);
58 if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) { 58 if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) {
59 usbmuxd_log(LOG_FATAL, "bind() failed: %s", strerror(errno)); 59 usbmuxd_log(LL_FATAL, "bind() failed: %s", strerror(errno));
60 return -1; 60 return -1;
61 } 61 }
62 62
63 // Start listening 63 // Start listening
64 if (listen(listenfd, 5) != 0) { 64 if (listen(listenfd, 5) != 0) {
65 usbmuxd_log(LOG_FATAL, "listen() failed: %s", strerror(errno)); 65 usbmuxd_log(LL_FATAL, "listen() failed: %s", strerror(errno));
66 return -1; 66 return -1;
67 } 67 }
68 68
69 return listenfd; 69 return listenfd;
70} 70}
71 71
72int main_loop(int listenfd)
73{
74 int to, cnt, i;
75 struct fdlist pollfds;
76
77 while(1) {
78 usbmuxd_log(LL_SPEW, "main_loop iteration");
79 to = usb_get_timeout();
80 usbmuxd_log(LL_SPEW, "USB timeout is %d ms", to);
81
82 fdlist_create(&pollfds);
83 usb_get_fds(&pollfds);
84 usbmuxd_log(LL_SPEW, "fd count is %d", pollfds.count);
85
86 cnt = poll(pollfds.fds, pollfds.count, to);
87 usbmuxd_log(LL_SPEW, "poll() returned %d", cnt);
88
89 if(cnt == 0) {
90 if(usb_process() < 0) {
91 usbmuxd_log(LL_FATAL, "usb_process() failed");
92 return -1;
93 }
94 } else {
95 for(i=0; i<pollfds.count; i++) {
96 if(pollfds.fds[i].revents) {
97 if(pollfds.owners[i] == FD_USB) {
98 if(usb_process() < 0) {
99 usbmuxd_log(LL_FATAL, "usb_process() failed");
100 return -1;
101 }
102 }
103 }
104 }
105 }
106 fdlist_free(&pollfds);
107 }
108}
109
72int main(int argc, char *argv[]) 110int main(int argc, char *argv[])
73{ 111{
74 int listenfd; 112 int listenfd;
75 int res; 113 int res;
76 114
77 usbmuxd_log(LOG_NOTICE, "usbmux v0.1 starting up"); 115 usbmuxd_log(LL_NOTICE, "usbmux v0.1 starting up");
78 116
79 usbmuxd_log(LOG_INFO, "Creating socket"); 117 usbmuxd_log(LL_INFO, "Creating socket");
80 listenfd = create_socket(); 118 listenfd = create_socket();
81 if(listenfd < 0) 119 if(listenfd < 0)
82 return 1; 120 return 1;
83 121
84 usbmuxd_log(LOG_INFO, "Initializing USB"); 122 usbmuxd_log(LL_INFO, "Initializing USB");
85 if((res = usb_init()) < 0) 123 if((res = usb_init()) < 0)
86 return 2; 124 return 2;
87 usbmuxd_log(LOG_INFO, "%d device%s detected", res, (res==1)?"":"s"); 125 usbmuxd_log(LL_INFO, "%d device%s detected", res, (res==1)?"":"s");
88 126
89 usbmuxd_log(LOG_NOTICE, "initialization complete"); 127 usbmuxd_log(LL_NOTICE, "Initialization complete");
128
129 res = main_loop(listenfd);
130 if(res < 0)
131 usbmuxd_log(LL_FATAL, "main_loop failed");
132
133 usbmuxd_log(LL_NOTICE, "usbmux shutting down");
134 usb_shutdown();
135 usbmuxd_log(LL_NOTICE, "Shutdown complete");
90 136
137 if(res < 0)
138 return -res;
91 return 0; 139 return 0;
92} 140}
diff --git a/usb-linux.c b/usb-linux.c
index 221ce33..0820ed9 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -24,11 +24,258 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 24
25#include <stdio.h> 25#include <stdio.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <stdlib.h> 27#include <stdint.h>
28#include <string.h>
28 29
29#include <libusb.h> 30#include <libusb.h>
30 31
31int usb_init(void) 32#include "usb.h"
33#include "log.h"
34#include "device.h"
35
36// interval for device connection/disconnection polling, in milliseconds
37// we need this because there is currently no asynchronous device discovery mechanism in libusb
38#define DEVICE_POLL_TIME 1000
39
40struct usb_device {
41 libusb_device_handle *dev;
42 uint8_t bus, address;
43 char serial[256];
44 int alive;
45};
46
47int num_devs;
48int device_id;
49struct usb_device *device_list;
50
51struct timeval next_dev_poll_time;
52
53static int alloc_device(void)
32{ 54{
55 int i;
56 for(i=0; i<num_devs; i++) {
57 if(!device_list[i].dev)
58 return i;
59 }
60 num_devs++;
61 device_list = realloc(device_list, sizeof(*device_list) * num_devs);
62 memset(&device_list[num_devs-1], 0, sizeof(*device_list));
63 return num_devs - 1;
64}
65
66static void usb_disconnect(struct usb_device *dev)
67{
68 if(!dev->dev) {
69 return;
70 }
71 libusb_release_interface(dev->dev, USB_INTERFACE);
72 libusb_close(dev->dev);
73 dev->dev = NULL;
74}
75
76static int usb_discover(void)
77{
78 int cnt, i, j, res;
79 int valid_count = 0;
80 libusb_device **devs;
81
82 cnt = libusb_get_device_list(NULL, &devs);
83 if(cnt < 0) {
84 usbmuxd_log(LL_FATAL, "Could not get device list: %d", cnt);
85 return cnt;
86 }
87
88 usbmuxd_log(LL_SPEW, "usb_discover: scanning %d devices", cnt);
89
90 for(j=0; j<num_devs; j++) {
91 device_list[j].alive = 0;
92 }
93 for(i=0; i<cnt; i++) {
94 // the following are non-blocking operations on the device list
95 libusb_device *dev = devs[i];
96 uint8_t bus = libusb_get_bus_number(dev);
97 uint8_t address = libusb_get_device_address(dev);
98 struct libusb_device_descriptor devdesc;
99 for(j=0; j<num_devs; j++) {
100 if(device_list[j].dev && device_list[j].bus == bus && device_list[j].address == address) {
101 valid_count++;
102 device_list[j].alive = 1;
103 break;
104 }
105 }
106 if(j < num_devs)
107 continue; //device already found
108 if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
109 usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %d", bus, address, res);
110 continue;
111 }
112 if(devdesc.idVendor != VID_APPLE)
113 continue;
114 if( (devdesc.idProduct != PID_IPHONE2G) &&
115 (devdesc.idProduct != PID_ITOUCH1G) &&
116 (devdesc.idProduct != PID_IPHONE3G))
117 continue;
118 libusb_device_handle *handle;
119 usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
120 // potentially blocking operations follow; they will only run when new devices are detected, which is acceptable
121 if((res = libusb_open(dev, &handle)) != 0) {
122 usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res);
123 continue;
124 }
125 if((res = libusb_set_configuration(handle, USB_CONFIGURATION)) != 0) {
126 usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %d", USB_CONFIGURATION, bus, address, res);
127 libusb_close(handle);
128 continue;
129 }
130 if((res = libusb_claim_interface(handle, USB_INTERFACE)) != 0) {
131 usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %d", USB_INTERFACE, bus, address, res);
132 libusb_close(handle);
133 continue;
134 }
135 int idx = alloc_device();
136
137 if((res = libusb_get_string_descriptor_ascii(handle, devdesc.iSerialNumber, (uint8_t *)device_list[idx].serial, 256)) <= 0) {
138 usbmuxd_log(LL_WARNING, "Could not get serial number for device %d-%d: %d", USB_INTERFACE, bus, address, res);
139 libusb_close(handle);
140 continue;
141 }
142 device_list[idx].serial[res] = 0;
143 device_list[idx].bus = bus;
144 device_list[idx].address = address;
145 device_list[idx].dev = handle;
146 device_list[idx].alive = 1;
147
148 device_add(&device_list[idx]);
149 valid_count++;
150 }
151 for(j=0; j<num_devs; j++) {
152 if(device_list[j].dev && !device_list[j].alive) {
153 device_remove(&device_list[j]);
154 usb_disconnect(&device_list[j]);
155 }
156 }
157 libusb_free_device_list(devs, 1);
158
159 gettimeofday(&next_dev_poll_time, NULL);
160 next_dev_poll_time.tv_usec += DEVICE_POLL_TIME * 1000;
161 next_dev_poll_time.tv_sec += next_dev_poll_time.tv_usec / 1000000;
162 next_dev_poll_time.tv_usec = next_dev_poll_time.tv_usec % 1000000;
163
164 return valid_count;
165}
166
167const char *usb_get_serial(struct usb_device *dev)
168{
169 if(!dev->dev) {
170 return NULL;
171 }
172 return dev->serial;
173}
174
175int usb_get_location(struct usb_device *dev)
176{
177 if(!dev->dev) {
178 return 0;
179 }
180 return (dev->bus << 16) | dev->address;
181}
182
183void usb_get_fds(struct fdlist *list)
184{
185 const struct libusb_pollfd **usbfds;
186 const struct libusb_pollfd **p;
187 usbfds = libusb_get_pollfds(NULL);
188 if(!usbfds) {
189 usbmuxd_log(LL_ERROR, "libusb_get_pollfds failed");
190 return;
191 }
192 p = usbfds;
193 while(*p) {
194 fdlist_add(list, FD_USB, (*p)->fd, (*p)->events);
195 p++;
196 }
197 free(usbfds);
198}
199
200static int dev_poll_remain_ms(void)
201{
202 int msecs;
203 struct timeval tv;
204 gettimeofday(&tv, NULL);
205 msecs = (next_dev_poll_time.tv_sec - tv.tv_sec) * 1000;
206 msecs += (next_dev_poll_time.tv_usec - tv.tv_usec) / 1000;
207 if(msecs < 0)
208 return 0;
209 return msecs;
210}
211
212int usb_get_timeout(void)
213{
214 struct timeval tv;
215 int msec;
216 int res;
217 int pollrem;
218 pollrem = dev_poll_remain_ms();
219 res = libusb_get_next_timeout(NULL, &tv);
220 if(res == 0)
221 return pollrem;
222 if(res < 0) {
223 usbmuxd_log(LL_ERROR, "libusb_get_next_timeout failed: %d", res);
224 return pollrem;
225 }
226 msec = tv.tv_sec * 1000;
227 msec += tv.tv_usec / 1000;
228 if(msec > pollrem)
229 return pollrem;
230 return msec;
231}
232
233int usb_process(void)
234{
235 int res;
236 struct timeval tv;
237 tv.tv_sec = tv.tv_usec = 0;
238 res = libusb_handle_events_timeout(NULL, &tv);
239 if(res < 0) {
240 usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res);
241 return res;
242 }
243 if(dev_poll_remain_ms() <= 0) {
244 res = usb_discover();
245 if(res < 0) {
246 usbmuxd_log(LL_ERROR, "usb_discover failed: %d", res);
247 return res;
248 }
249 }
33 return 0; 250 return 0;
34} 251}
252
253int usb_init(void)
254{
255 int res;
256 usbmuxd_log(LL_DEBUG, "usb_init for linux / libusb 1.0");
257
258 res = libusb_init(NULL);
259 if(res != 0) {
260 usbmuxd_log(LL_FATAL, "libusb_init failed: %d", res);
261 return -1;
262 }
263
264 device_id = 1;
265 num_devs = 1;
266 device_list = malloc(sizeof(*device_list) * num_devs);
267 memset(device_list, 0, sizeof(*device_list) * num_devs);
268
269 return usb_discover();
270}
271
272void usb_shutdown(void)
273{
274 int i;
275 usbmuxd_log(LL_DEBUG, "usb_shutdown");
276 for(i=0; i<num_devs; i++)
277 usb_disconnect(&device_list[i]);
278 free(device_list);
279 device_list = NULL;
280 libusb_exit(NULL);
281}
diff --git a/usb.h b/usb.h
index cf25c3a..25243d8 100644
--- a/usb.h
+++ b/usb.h
@@ -21,9 +21,27 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21#ifndef __USB_H__ 21#ifndef __USB_H__
22#define __USB_H__ 22#define __USB_H__
23 23
24#include "utils.h"
25
24#define BULK_IN 0x85 26#define BULK_IN 0x85
25#define BULK_OUT 0x04 27#define BULK_OUT 0x04
26 28
29#define VID_APPLE 0x5ac
30#define PID_IPHONE2G 0x1290
31#define PID_ITOUCH1G 0x1291
32#define PID_IPHONE3G 0x1292
33
34#define USB_CONFIGURATION 3
35#define USB_INTERFACE 1
36
37struct usb_device;
38
27int usb_init(void); 39int usb_init(void);
40void usb_shutdown(void);
41const char *usb_get_serial(struct usb_device *dev);
42int usb_get_location(struct usb_device *dev);
43void usb_get_fds(struct fdlist *list);
44int usb_get_timeout(void);
45int usb_process(void);
28 46
29#endif 47#endif
diff --git a/utils.c b/utils.c
index c3d5c50..41c3bcb 100644
--- a/utils.c
+++ b/utils.c
@@ -25,14 +25,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25#include <stdlib.h> 25#include <stdlib.h>
26#include "utils.h" 26#include "utils.h"
27 27
28void fdlist_create(fdlist *list) 28void fdlist_create(struct fdlist *list)
29{ 29{
30 list->count = 0; 30 list->count = 0;
31 list->capacity = 4; 31 list->capacity = 4;
32 list->owners = malloc(sizeof(*list->owners) * list->capacity); 32 list->owners = malloc(sizeof(*list->owners) * list->capacity);
33 list->fds = malloc(sizeof(*list->fds) * list->capacity); 33 list->fds = malloc(sizeof(*list->fds) * list->capacity);
34} 34}
35void fdlist_add(fdlist *list, enum fdowner owner, int fd, short events) 35void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events)
36{ 36{
37 if(list->count == list->capacity) { 37 if(list->count == list->capacity) {
38 list->capacity *= 2; 38 list->capacity *= 2;
@@ -46,7 +46,7 @@ void fdlist_add(fdlist *list, enum fdowner owner, int fd, short events)
46 list->count++; 46 list->count++;
47} 47}
48 48
49void fdlist_free(fdlist *list) 49void fdlist_free(struct fdlist *list)
50{ 50{
51 list->count = 0; 51 list->count = 0;
52 list->capacity = 0; 52 list->capacity = 0;
diff --git a/utils.h b/utils.h
index 465487d..9a6d566 100644
--- a/utils.h
+++ b/utils.h
@@ -18,8 +18,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18
19*/ 19*/
20 20
21#ifndef __LOG_H__ 21#ifndef __UTILS_H__
22#define __LOG_H__ 22#define __UTILS_H__
23 23
24#include <poll.h> 24#include <poll.h>
25 25
@@ -29,19 +29,17 @@ enum fdowner {
29 FD_USB 29 FD_USB
30}; 30};
31 31
32typedef struct { 32struct fdlist {
33 int count; 33 int count;
34 int capacity; 34 int capacity;
35 enum fdowner *owners; 35 enum fdowner *owners;
36 struct pollfd *fds; 36 struct pollfd *fds;
37} fdlist; 37};
38 38
39void fdlist_create(fdlist *list); 39void fdlist_create(struct fdlist *list);
40void fdlist_add(fdlist *list, enum fdowner owner, int fd, short events); 40void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events);
41void fdlist_free(fdlist *list); 41void fdlist_free(struct fdlist *list);
42 42
43#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) 43#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
44 44
45
46
47#endif 45#endif