blob: 5ffc155357d077bf1e90895103949e9d26f6ccd5 [file] [log] [blame]
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +09001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#include <Python.h>
21#include "types.h"
22#include "binary.h"
23#include "compact.h"
24#include <stdint.h>
25#include <sys/resource.h>
26
27// TODO(dreiss): defval appears to be unused. Look into removing it.
28// TODO(dreiss): Make parse_spec_args recursive, and cache the output
29// permanently in the object. (Malloc and orphan.)
30// TODO(dreiss): Why do we need cStringIO for reading, why not just char*?
31// Can cStringIO let us work with a BufferedTransport?
32// TODO(dreiss): Don't ignore the rv from cwrite (maybe).
33
34// Doing a benchmark shows that interning actually makes a difference, amazingly.
35
36/** Pointer to interned string to speed up attribute lookup. */
37PyObject* INTERN_STRING(TFrozenDict);
38PyObject* INTERN_STRING(cstringio_buf);
39PyObject* INTERN_STRING(cstringio_refill);
40static PyObject* INTERN_STRING(string_length_limit);
41static PyObject* INTERN_STRING(container_length_limit);
42static PyObject* INTERN_STRING(trans);
43
44namespace apache {
45namespace thrift {
46namespace py {
47
48template <typename T>
49static PyObject* encode_impl(PyObject* args) {
50 if (!args)
51 return NULL;
52
53 PyObject* enc_obj = NULL;
54 PyObject* type_args = NULL;
55 if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) {
56 return NULL;
57 }
58 if (!enc_obj || !type_args) {
59 return NULL;
60 }
61
62 T protocol;
63 if (!protocol.prepareEncodeBuffer() || !protocol.encodeValue(enc_obj, T_STRUCT, type_args)) {
64 return NULL;
65 }
66
67 return protocol.getEncodedValue();
68}
69
70static inline long as_long_then_delete(PyObject* value, long default_value) {
71 ScopedPyObject scope(value);
72 long v = PyInt_AsLong(value);
73 if (INT_CONV_ERROR_OCCURRED(v)) {
74 PyErr_Clear();
75 return default_value;
76 }
77 return v;
78}
79
80template <typename T>
81static PyObject* decode_impl(PyObject* args) {
82 PyObject* output_obj = NULL;
83 PyObject* oprot = NULL;
84 PyObject* typeargs = NULL;
85 if (!PyArg_ParseTuple(args, "OOO", &output_obj, &oprot, &typeargs)) {
86 return NULL;
87 }
88
89 T protocol;
90 protocol.setStringLengthLimit(
91 as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(string_length_limit)), INT32_MAX));
92 protocol.setContainerLengthLimit(
93 as_long_then_delete(PyObject_GetAttr(oprot, INTERN_STRING(container_length_limit)),
94 INT32_MAX));
95 ScopedPyObject transport(PyObject_GetAttr(oprot, INTERN_STRING(trans)));
96 if (!transport) {
97 return NULL;
98 }
99
100 StructTypeArgs parsedargs;
101 if (!parse_struct_args(&parsedargs, typeargs)) {
102 return NULL;
103 }
104
105 if (!protocol.prepareDecodeBufferFromTransport(transport.get())) {
106 return NULL;
107 }
108
109 return protocol.readStruct(output_obj, parsedargs.klass, parsedargs.spec);
110}
111}
112}
113}
114
115using namespace apache::thrift::py;
116
117/* -- PYTHON MODULE SETUP STUFF --- */
118
119extern "C" {
120
121static PyObject* encode_binary(PyObject*, PyObject* args) {
122 return encode_impl<BinaryProtocol>(args);
123}
124
125static PyObject* decode_binary(PyObject*, PyObject* args) {
126 return decode_impl<BinaryProtocol>(args);
127}
128
129static PyObject* encode_compact(PyObject*, PyObject* args) {
130 return encode_impl<CompactProtocol>(args);
131}
132
133static PyObject* decode_compact(PyObject*, PyObject* args) {
134 return decode_impl<CompactProtocol>(args);
135}
136
137static PyMethodDef ThriftFastBinaryMethods[] = {
138 {"encode_binary", encode_binary, METH_VARARGS, ""},
139 {"decode_binary", decode_binary, METH_VARARGS, ""},
140 {"encode_compact", encode_compact, METH_VARARGS, ""},
141 {"decode_compact", decode_compact, METH_VARARGS, ""},
142 {NULL, NULL, 0, NULL} /* Sentinel */
143};
144
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900145#if PY_MAJOR_VERSION >= 3
146
147static struct PyModuleDef ThriftFastBinaryDef = {PyModuleDef_HEAD_INIT,
148 "thrift.protocol.fastbinary",
149 NULL,
150 0,
151 ThriftFastBinaryMethods,
152 NULL,
153 NULL,
154 NULL,
155 NULL};
156
157#define INITERROR return NULL;
158
159PyObject* PyInit_fastbinary() {
160
161#else
162
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900163#define INITERROR return;
164
165void initfastbinary() {
166
167 PycString_IMPORT;
168 if (PycStringIO == NULL)
169 INITERROR
170
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900171#endif
172
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900173 const rlim_t kStackSize = 16 * 1024 * 1024; // min stack size = 16 MB
174 struct rlimit rl;
175 int result;
176
177 result = getrlimit(RLIMIT_STACK, &rl);
178 if (result == 0) {
179 if (rl.rlim_cur < kStackSize) {
180 rl.rlim_cur = kStackSize;
181 result = setrlimit(RLIMIT_STACK, &rl);
182 if (result != 0) {
183 fprintf(stderr, "setrlimit returned result = %d\n", result);
184 }
185 }
186 }
187
188#define INIT_INTERN_STRING(value) \
189 do { \
190 INTERN_STRING(value) = PyString_InternFromString(#value); \
191 if (!INTERN_STRING(value)) \
192 INITERROR \
193 } while (0)
194
195 INIT_INTERN_STRING(TFrozenDict);
196 INIT_INTERN_STRING(cstringio_buf);
197 INIT_INTERN_STRING(cstringio_refill);
198 INIT_INTERN_STRING(string_length_limit);
199 INIT_INTERN_STRING(container_length_limit);
200 INIT_INTERN_STRING(trans);
201#undef INIT_INTERN_STRING
202
203 PyObject* module =
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900204#if PY_MAJOR_VERSION >= 3
205 PyModule_Create(&ThriftFastBinaryDef);
206#else
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900207 Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods);
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900208#endif
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900209 if (module == NULL)
210 INITERROR;
211
Nobuaki Sukegawa7af189a2016-02-11 16:21:01 +0900212#if PY_MAJOR_VERSION >= 3
213 return module;
214#endif
Nobuaki Sukegawa6525f6a2016-02-11 13:58:39 +0900215}
216}