Skip to content

Commit 12c1200

Browse files
committed
Fixed sendfile file descriptor leak.
1 parent 6c78671 commit 12c1200

File tree

6 files changed

+60
-41
lines changed

6 files changed

+60
-41
lines changed

examples/event/stdin.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
swoole_event_add(STDIN, function($fp) {
3+
echo "STDIN: ".fread($fp, 8192);
4+
});

include/Connection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ swBuffer_trunk* swConnection_get_out_buffer(swConnection *conn, uint32_t type);
3838
swBuffer_trunk* swConnection_get_in_buffer(swConnection *conn);
3939
int swConnection_sendfile(swConnection *conn, char *filename);
4040
int swConnection_onSendfile(swConnection *conn, swBuffer_trunk *chunk);
41+
void swConnection_sendfile_destructor(swBuffer_trunk *chunk);
4142
char* swConnection_get_ip(swConnection *conn);
4243
int swConnection_get_port(swConnection *conn);
4344

include/buffer.h

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,31 @@ enum swBufferChunk
3131

3232
typedef struct _swBuffer_trunk
3333
{
34-
uint32_t type;
35-
uint32_t length;
36-
uint32_t offset;
37-
union
38-
{
39-
void *ptr;
40-
struct
41-
{
42-
uint32_t val1;
43-
uint32_t val2;
44-
} data;
45-
} store;
46-
uint32_t size;
47-
struct _swBuffer_trunk *next;
34+
uint32_t type;
35+
uint32_t length;
36+
uint32_t offset;
37+
union
38+
{
39+
void *ptr;
40+
struct
41+
{
42+
uint32_t val1;
43+
uint32_t val2;
44+
} data;
45+
} store;
46+
uint32_t size;
47+
void (*destroy)(struct _swBuffer_trunk *chunk);
48+
struct _swBuffer_trunk *next;
4849
} swBuffer_trunk;
4950

5051
typedef struct _swBuffer
5152
{
52-
int fd;
53-
uint8_t trunk_num; //trunk数量
54-
uint16_t trunk_size;
55-
uint32_t length;
56-
swBuffer_trunk *head;
57-
swBuffer_trunk *tail;
53+
int fd;
54+
uint8_t trunk_num; //trunk数量
55+
uint16_t trunk_size;
56+
uint32_t length;
57+
swBuffer_trunk *head;
58+
swBuffer_trunk *tail;
5859
} swBuffer;
5960

6061
#define swBuffer_get_trunk(buffer) (buffer->head)

src/core/socket.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ int swSocket_sendfile_sync(int sock, char *filename, double timeout)
4444
{
4545
if (swSocket_wait(sock, timeout_ms, SW_EVENT_WRITE) < 0)
4646
{
47+
close(file_fd);
4748
return SW_ERR;
4849
}
4950
else
@@ -52,7 +53,8 @@ int swSocket_sendfile_sync(int sock, char *filename, double timeout)
5253
n = swoole_sendfile(sock, file_fd, &offset, sendn);
5354
if (n <= 0)
5455
{
55-
swWarn("sendfile() failed. Error: %s[%d]", strerror(errno), errno);
56+
close(file_fd);
57+
swSysError("sendfile(%d, %s) failed.", sock, filename);
5658
return SW_ERR;
5759
}
5860
else
@@ -61,6 +63,7 @@ int swSocket_sendfile_sync(int sock, char *filename, double timeout)
6163
}
6264
}
6365
}
66+
close(file_fd);
6467
return SW_OK;
6568
}
6669

src/memory/Buffer.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,9 @@ swBuffer_trunk *swBuffer_new_trunk(swBuffer *buffer, uint32_t type, uint32_t siz
8282
/**
8383
* pop the head chunk
8484
*/
85-
void swBuffer_pop_trunk(swBuffer *buffer, swBuffer_trunk *trunk)
85+
void swBuffer_pop_trunk(swBuffer *buffer, swBuffer_trunk *chunk)
8686
{
87-
//only one trunk
88-
if (trunk->next == NULL)
87+
if (chunk->next == NULL)
8988
{
9089
buffer->head = NULL;
9190
buffer->tail = NULL;
@@ -94,16 +93,19 @@ void swBuffer_pop_trunk(swBuffer *buffer, swBuffer_trunk *trunk)
9493
}
9594
else
9695
{
97-
buffer->head = trunk->next;
98-
buffer->length -= trunk->length;
96+
buffer->head = chunk->next;
97+
buffer->length -= chunk->length;
9998
buffer->trunk_num--;
10099
}
101-
102-
if (trunk->type == SW_CHUNK_DATA)
100+
if (chunk->type == SW_CHUNK_DATA)
101+
{
102+
sw_free(chunk->store.ptr);
103+
}
104+
if (chunk->destroy)
103105
{
104-
sw_free(trunk->store.ptr);
106+
chunk->destroy(chunk);
105107
}
106-
sw_free(trunk);
108+
sw_free(chunk);
107109
}
108110

109111
/**

src/network/Connection.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ int swConnection_onSendfile(swConnection *conn, swBuffer_trunk *chunk)
8181
if (task->offset >= task->filesize)
8282
{
8383
swBuffer_pop_trunk(conn->out_buffer, chunk);
84-
close(task->fd);
85-
sw_free(task);
8684

8785
#ifdef HAVE_TCP_NOPUSH
8886
if (conn->tcp_nopush)
@@ -210,6 +208,14 @@ int swConnection_get_port(swConnection *conn)
210208
}
211209
}
212210

211+
void swConnection_sendfile_destructor(swBuffer_trunk *chunk)
212+
{
213+
swTask_sendfile *task = chunk->store.ptr;
214+
close(task->fd);
215+
sw_free(task->filename);
216+
sw_free(task);
217+
}
218+
213219
int swConnection_sendfile(swConnection *conn, char *filename)
214220
{
215221
if (conn->out_buffer == NULL)
@@ -221,6 +227,7 @@ int swConnection_sendfile(swConnection *conn, char *filename)
221227
}
222228
}
223229

230+
swBuffer_trunk error_chunk;
224231
swTask_sendfile *task = sw_malloc(sizeof(swTask_sendfile));
225232
if (task == NULL)
226233
{
@@ -238,28 +245,29 @@ int swConnection_sendfile(swConnection *conn, char *filename)
238245
swSysError("open(%s) failed.", task->filename);
239246
return SW_ERR;
240247
}
248+
task->fd = file_fd;
241249

242250
struct stat file_stat;
243251
if (fstat(file_fd, &file_stat) < 0)
244252
{
245-
free(task->filename);
246-
free(task);
247253
swSysError("fstat(%s) failed.", filename);
254+
error_chunk.store.ptr = task;
255+
swConnection_sendfile_destructor(&error_chunk);
248256
return SW_ERR;
249257
}
258+
task->filesize = file_stat.st_size;
250259

251-
swBuffer_trunk *trunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_SENDFILE, 0);
252-
if (trunk == NULL)
260+
swBuffer_trunk *chunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_SENDFILE, 0);
261+
if (chunk == NULL)
253262
{
254-
free(task->filename);
255-
free(task);
256263
swWarn("get out_buffer trunk failed.");
264+
error_chunk.store.ptr = task;
265+
swConnection_sendfile_destructor(&error_chunk);
257266
return SW_ERR;
258267
}
259268

260-
task->filesize = file_stat.st_size;
261-
task->fd = file_fd;
262-
trunk->store.ptr = (void *) task;
269+
chunk->store.ptr = (void *) task;
270+
chunk->destroy = swConnection_sendfile_destructor;
263271

264272
return SW_OK;
265273
}

0 commit comments

Comments
 (0)