1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 
11 
12 /* FreeBSD 3.0 at least */
13 char    ngx_freebsd_kern_ostype[16];
14 char    ngx_freebsd_kern_osrelease[128];
15 int     ngx_freebsd_kern_osreldate;
16 int     ngx_freebsd_hw_ncpu;
17 int     ngx_freebsd_kern_ipc_somaxconn;
18 u_long  ngx_freebsd_net_inet_tcp_sendspace;
19 
20 /* FreeBSD 4.9 */
21 int     ngx_freebsd_machdep_hlt_logical_cpus;
22 
23 
24 ngx_uint_t  ngx_freebsd_sendfile_nbytes_bug;
25 ngx_uint_t  ngx_freebsd_use_tcp_nopush;
26 
27 ngx_uint_t  ngx_debug_malloc;
28 
29 
30 static ngx_os_io_t ngx_freebsd_io = {
31     ngx_unix_recv,
32     ngx_readv_chain,
33     ngx_udp_unix_recv,
34     ngx_unix_send,
35     ngx_udp_unix_send,
36     ngx_udp_unix_sendmsg_chain,
37 #if (NGX_HAVE_SENDFILE)
38     ngx_freebsd_sendfile_chain,
39     NGX_IO_SENDFILE
40 #else
41     ngx_writev_chain,
42     0
43 #endif
44 };
45 
46 
47 typedef struct {
48     char        *name;
49     void        *value;
50     size_t       size;
51     ngx_uint_t   exists;
52 } sysctl_t;
53 
54 
55 sysctl_t sysctls[] = {
56     { "hw.ncpu",
57       &ngx_freebsd_hw_ncpu,
58       sizeof(ngx_freebsd_hw_ncpu), 0 },
59 
60     { "machdep.hlt_logical_cpus",
61       &ngx_freebsd_machdep_hlt_logical_cpus,
62       sizeof(ngx_freebsd_machdep_hlt_logical_cpus), 0 },
63 
64     { "net.inet.tcp.sendspace",
65       &ngx_freebsd_net_inet_tcp_sendspace,
66       sizeof(ngx_freebsd_net_inet_tcp_sendspace), 0 },
67 
68     { "kern.ipc.somaxconn",
69       &ngx_freebsd_kern_ipc_somaxconn,
70       sizeof(ngx_freebsd_kern_ipc_somaxconn), 0 },
71 
72     { NULL, NULL, 0, 0 }
73 };
74 
75 
76 void
ngx_debug_init(void)77 ngx_debug_init(void)
78 {
79 #if (NGX_DEBUG_MALLOC)
80 
81 #if __FreeBSD_version >= 500014 && __FreeBSD_version < 1000011
82     _malloc_options = "J";
83 #elif __FreeBSD_version < 500014
84     malloc_options = "J";
85 #endif
86 
87     ngx_debug_malloc = 1;
88 
89 #else
90     char  *mo;
91 
92     mo = getenv("MALLOC_OPTIONS");
93 
94     if (mo && ngx_strchr(mo, 'J')) {
95         ngx_debug_malloc = 1;
96     }
97 #endif
98 }
99 
100 
101 ngx_int_t
ngx_os_specific_init(ngx_log_t * log)102 ngx_os_specific_init(ngx_log_t *log)
103 {
104     int         version;
105     size_t      size;
106     ngx_err_t   err;
107     ngx_uint_t  i;
108 
109     size = sizeof(ngx_freebsd_kern_ostype);
110     if (sysctlbyname("kern.ostype",
111                      ngx_freebsd_kern_ostype, &size, NULL, 0) == -1) {
112         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
113                       "sysctlbyname(kern.ostype) failed");
114 
115         if (ngx_errno != NGX_ENOMEM) {
116             return NGX_ERROR;
117         }
118 
119         ngx_freebsd_kern_ostype[size - 1] = '\0';
120     }
121 
122     size = sizeof(ngx_freebsd_kern_osrelease);
123     if (sysctlbyname("kern.osrelease",
124                      ngx_freebsd_kern_osrelease, &size, NULL, 0) == -1) {
125         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
126                       "sysctlbyname(kern.osrelease) failed");
127 
128         if (ngx_errno != NGX_ENOMEM) {
129             return NGX_ERROR;
130         }
131 
132         ngx_freebsd_kern_osrelease[size - 1] = '\0';
133     }
134 
135 
136     size = sizeof(int);
137     if (sysctlbyname("kern.osreldate",
138                      &ngx_freebsd_kern_osreldate, &size, NULL, 0) == -1) {
139         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
140                       "sysctlbyname(kern.osreldate) failed");
141         return NGX_ERROR;
142     }
143 
144     version = ngx_freebsd_kern_osreldate;
145 
146 
147 #if (NGX_HAVE_SENDFILE)
148 
149     /*
150      * The determination of the sendfile() "nbytes bug" is complex enough.
151      * There are two sendfile() syscalls: a new #393 has no bug while
152      * an old #336 has the bug in some versions and has not in others.
153      * Besides libc_r wrapper also emulates the bug in some versions.
154      * There is no way to say exactly if syscall #336 in FreeBSD circa 4.6
155      * has the bug.  We use the algorithm that is correct at least for
156      * RELEASEs and for syscalls only (not libc_r wrapper).
157      *
158      * 4.6.1-RELEASE and below have the bug
159      * 4.6.2-RELEASE and above have the new syscall
160      *
161      * We detect the new sendfile() syscall available at the compile time
162      * to allow an old binary to run correctly on an updated FreeBSD system.
163      */
164 
165 #if (__FreeBSD__ == 4 && __FreeBSD_version >= 460102) \
166     || __FreeBSD_version == 460002 || __FreeBSD_version >= 500039
167 
168     /* a new syscall without the bug */
169 
170     ngx_freebsd_sendfile_nbytes_bug = 0;
171 
172 #else
173 
174     /* an old syscall that may have the bug */
175 
176     ngx_freebsd_sendfile_nbytes_bug = 1;
177 
178 #endif
179 
180 #endif /* NGX_HAVE_SENDFILE */
181 
182 
183     if ((version < 500000 && version >= 440003) || version >= 500017) {
184         ngx_freebsd_use_tcp_nopush = 1;
185     }
186 
187 
188     for (i = 0; sysctls[i].name; i++) {
189         size = sysctls[i].size;
190 
191         if (sysctlbyname(sysctls[i].name, sysctls[i].value, &size, NULL, 0)
192             == 0)
193         {
194             sysctls[i].exists = 1;
195             continue;
196         }
197 
198         err = ngx_errno;
199 
200         if (err == NGX_ENOENT) {
201             continue;
202         }
203 
204         ngx_log_error(NGX_LOG_ALERT, log, err,
205                       "sysctlbyname(%s) failed", sysctls[i].name);
206         return NGX_ERROR;
207     }
208 
209     if (ngx_freebsd_machdep_hlt_logical_cpus) {
210         ngx_ncpu = ngx_freebsd_hw_ncpu / 2;
211 
212     } else {
213         ngx_ncpu = ngx_freebsd_hw_ncpu;
214     }
215 
216     if (version < 600008 && ngx_freebsd_kern_ipc_somaxconn > 32767) {
217         ngx_log_error(NGX_LOG_ALERT, log, 0,
218                       "sysctl kern.ipc.somaxconn must be less than 32768");
219         return NGX_ERROR;
220     }
221 
222     ngx_tcp_nodelay_and_tcp_nopush = 1;
223 
224     ngx_os_io = ngx_freebsd_io;
225 
226     return NGX_OK;
227 }
228 
229 
230 void
ngx_os_specific_status(ngx_log_t * log)231 ngx_os_specific_status(ngx_log_t *log)
232 {
233     u_long      value;
234     ngx_uint_t  i;
235 
236     ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s",
237                   ngx_freebsd_kern_ostype, ngx_freebsd_kern_osrelease);
238 
239 #ifdef __DragonFly_version
240     ngx_log_error(NGX_LOG_NOTICE, log, 0,
241                   "kern.osreldate: %d, built on %d",
242                   ngx_freebsd_kern_osreldate, __DragonFly_version);
243 #else
244     ngx_log_error(NGX_LOG_NOTICE, log, 0,
245                   "kern.osreldate: %d, built on %d",
246                   ngx_freebsd_kern_osreldate, __FreeBSD_version);
247 #endif
248 
249     for (i = 0; sysctls[i].name; i++) {
250         if (sysctls[i].exists) {
251             if (sysctls[i].size == sizeof(long)) {
252                 value = *(long *) sysctls[i].value;
253 
254             } else {
255                 value = *(int *) sysctls[i].value;
256             }
257 
258             ngx_log_error(NGX_LOG_NOTICE, log, 0, "%s: %l",
259                           sysctls[i].name, value);
260         }
261     }
262 }
263