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