1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /* Monkey HTTP Server
4 * ==================
5 * Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #define _GNU_SOURCE
21
22 #include <stdio.h>
23 #include <string.h>
24
25 #include <sys/types.h>
26 #include <fcntl.h>
27
28 #ifdef _WIN32
29 #include <winsock2.h>
30 #else
31 #include <arpa/inet.h>
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #endif
35
36 #if defined (__linux__)
37 #include <sys/sendfile.h>
38 #endif
39
40 #include <monkey/mk_api.h>
41
mk_liana_plugin_init(struct plugin_api ** api,char * confdir)42 int mk_liana_plugin_init(struct plugin_api **api, char *confdir)
43 {
44 (void) confdir;
45 mk_api = *api;
46 return 0;
47 }
48
mk_liana_plugin_exit()49 int mk_liana_plugin_exit()
50 {
51 return 0;
52 }
53
mk_liana_read(int socket_fd,void * buf,int count)54 int mk_liana_read(int socket_fd, void *buf, int count)
55 {
56 return recv(socket_fd, (void*)buf, count, 0);
57 }
58
mk_liana_write(int socket_fd,const void * buf,size_t count)59 int mk_liana_write(int socket_fd, const void *buf, size_t count )
60 {
61 ssize_t bytes_sent = -1;
62
63 bytes_sent = send(socket_fd, buf, count, 0);
64
65 return bytes_sent;
66 }
67
mk_liana_writev(int socket_fd,struct mk_iov * mk_io)68 int mk_liana_writev(int socket_fd, struct mk_iov *mk_io)
69 {
70 ssize_t bytes_sent = -1;
71
72 bytes_sent = mk_api->iov_send(socket_fd, mk_io);
73
74 return bytes_sent;
75 }
76
mk_liana_close(int socket_fd)77 int mk_liana_close(int socket_fd)
78 {
79 #ifdef _WIN32
80 return closesocket(socket_fd);
81 #else
82 return close(socket_fd);
83 #endif
84 }
85
mk_liana_send_file(int socket_fd,int file_fd,off_t * file_offset,size_t file_count)86 int mk_liana_send_file(int socket_fd, int file_fd, off_t *file_offset,
87 size_t file_count)
88 {
89 ssize_t bytes_written = 0;
90 ssize_t to_be_sent = -1;
91 ssize_t send_ret = -1;
92 ssize_t ret = -1;
93
94 #if defined (__linux__)
95 ret = sendfile(socket_fd, file_fd, file_offset, file_count);
96 if (ret == -1 && errno != EAGAIN) {
97 PLUGIN_TRACE("[FD %i] error from sendfile(): %s",
98 socket_fd, strerror(errno));
99 }
100 return ret;
101 #elif defined (__APPLE__)
102 off_t offset = *file_offset;
103 off_t len = (off_t) file_count;
104
105 ret = sendfile(file_fd, socket_fd, offset, &len, NULL, 0);
106 if (ret == -1 && errno != EAGAIN) {
107 PLUGIN_TRACE("[FD %i] error from sendfile(): %s",
108 socket_fd, strerror(errno));
109 }
110 else if (len > 0) {
111 *file_offset += len;
112 return len;
113 }
114 return ret;
115 #elif defined (__FreeBSD__) || defined(__DragonFly__)
116 off_t offset = *file_offset;
117 off_t len = (off_t) file_count;
118
119 ret = sendfile(file_fd, socket_fd, offset, len, NULL, 0, 0);
120 if (ret == -1 && errno != EAGAIN) {
121 PLUGIN_TRACE("[FD %i] error from sendfile(): %s",
122 socket_fd, strerror(errno));
123 }
124 else if (len > 0) {
125 *file_offset += len;
126 return len;
127 }
128 return ret;
129 #else
130 #pragma message ("This is a terrible sendfile \"implementation\" and just a crutch")
131
132 uint8_t temporary_buffer[1024];
133
134 if (NULL != file_offset) {
135 lseek(file_fd, *file_offset, SEEK_SET);
136 }
137
138 while (1) {
139 memset(temporary_buffer, 0, sizeof(temporary_buffer));
140
141 ret = read(file_fd, temporary_buffer, sizeof(temporary_buffer));
142
143 if (0 == ret)
144 {
145 return bytes_written;
146 }
147 else if (0 > ret)
148 {
149 return -1;
150 }
151 else if (0 < ret)
152 {
153 to_be_sent = ret;
154
155 while (to_be_sent > 0)
156 {
157 send_ret = send(file_fd, &temporary_buffer[ret - to_be_sent], to_be_sent, 0);
158
159 if (-1 == send_ret)
160 {
161 if (EAGAIN != errno &&
162 EWOULDBLOCK != errno)
163 {
164 return -1;
165 }
166 }
167 else
168 {
169 bytes_written += send_ret;
170 to_be_sent -= send_ret;
171 }
172 }
173 }
174 }
175 #endif
176 }
177
178 /* Network Layer plugin Callbacks */
179 struct mk_plugin_network mk_plugin_network_liana = {
180 .read = mk_liana_read,
181 .write = mk_liana_write,
182 .writev = mk_liana_writev,
183 .close = mk_liana_close,
184 .send_file = mk_liana_send_file,
185 .buffer_size = MK_REQUEST_CHUNK
186 };
187
188 struct mk_plugin mk_plugin_liana = {
189 /* Identification */
190 .shortname = "liana",
191 .name = "Liana Network Layer",
192 .version = MK_VERSION_STR,
193 .hooks = MK_PLUGIN_NETWORK_LAYER,
194
195 /* Init / Exit */
196 .init_plugin = mk_liana_plugin_init,
197 .exit_plugin = mk_liana_plugin_exit,
198
199 /* Init Levels */
200 .master_init = NULL,
201 .worker_init = NULL,
202
203 /* Type */
204 .network = &mk_plugin_network_liana,
205
206 /* Capabilities */
207 .capabilities = MK_CAP_SOCK_PLAIN
208 };
209