1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
|
## AWS C Common
[![GitHub](https://img.shields.io/github/license/awslabs/aws-c-common.svg)](https://github.com/awslabs/aws-c-common/blob/main/LICENSE)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/awslabs/aws-c-common.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/awslabs/aws-c-common/context:cpp)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/awslabs/aws-c-common.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/awslabs/aws-c-common/alerts/)
Core c99 package for AWS SDK for C. Includes cross-platform primitives, configuration, data structures, and error handling.
## License
This library is licensed under the Apache 2.0 License.
## Usage
### Building
aws-c-common uses CMake for setting up build environments. This library has no non-kernel dependencies so the build is quite
simple.
For example:
git clone git@github.com:awslabs/aws-c-common.git aws-c-common
mkdir aws-c-common-build
cd aws-c-common-build
cmake ../aws-c-common
make -j 12
make test
sudo make install
Keep in mind that CMake supports multiple build systems, so for each platform you can pass your own build system
as the `-G` option. For example:
cmake -GNinja ../aws-c-common
ninja build
ninja test
sudo ninja install
Or on windows,
cmake -G "Visual Studio 14 2015 Win64" ../aws-c-common
msbuild.exe ALL_BUILD.vcproj
### CMake Options
* -DCMAKE_CLANG_TIDY=/path/to/clang-tidy (or just clang-tidy or clang-tidy-7.0 if it is in your PATH) - Runs clang-tidy as part of your build.
* -DENABLE_SANITIZERS=ON - Enables gcc/clang sanitizers, by default this adds -fsanitizer=address,undefined to the compile flags for projects that call aws_add_sanitizers.
* -DENABLE_FUZZ_TESTS=ON - Includes fuzz tests in the unit test suite. Off by default, because fuzz tests can take a long time. Set -DFUZZ_TESTS_MAX_TIME=N to determine how long to run each fuzz test (default 60s).
* -DCMAKE_INSTALL_PREFIX=/path/to/install - Standard way of installing to a user defined path. If specified when configuring aws-c-common, ensure the same prefix is specified when configuring other aws-c-* SDKs.
* -DSTATIC_CRT=ON - On MSVC, use /MT(d) to link MSVCRT
### API style and conventions
Every API has a specific set of styles and conventions. We'll outline them here. These conventions are followed in every
library in the AWS C SDK ecosystem.
#### Error handling
Every function that returns an `int` type, returns `AWS_OP_SUCCESS` ( 0 ) or `AWS_OP_ERR` (-1) on failure. To retrieve
the error code, use the function `aws_last_error()`. Each error code also has a corresponding error string that can be
accessed via the `aws_error_str()` function.
In addition, you can install both a global and a thread local error handler by using the `aws_set_global_error_handler_fn()`
and `aws_set_thread_local_error_handler_fn()` functions.
All error functions are in the `include/aws/common/error.h` header file.
#### Naming
Any function that allocates and initializes an object will be suffixed with `new` (e.g. `aws_myobj_new()`). Similarly, these objects will always
have a corresponding function with a `destroy` suffix. The `new` functions will return the allocated object
on success and `NULL` on failure. To respond to the error, call `aws_last_error()`. If several `new` or `destroy`
functions are available, the variants should be named like `new_x` or `destroy_x` (e.g. `aws_myobj_new_copy()` or `aws_myobj_destroy_secure()`).
Any function that initializes an existing object will be suffixed with `init` (e.g. `aws_myobj_init()`. These objects will have a corresponding
`clean_up` function if necessary. In these cases, you are responsible for making the decisions for how your object is
allocated. The `init` functions return `AWS_OP_SUCCESS` ( 0 ) or `AWS_OP_ERR` (-1) on failure. If several `init` or
`clean_up` functions are available, they should be named like `init_x` or `clean_up_x` (e.g. `aws_myobj_init_static()` or
`aws_myobj_clean_up_secure()`).
## Contributing
If you are contributing to this code-base, first off, THANK YOU!. There are a few things to keep in mind to minimize the
pull request turn around time.
### Coding "guidelines"
These "guidelines" are followed in every library in the AWS C SDK ecosystem.
#### Memory Management
* All APIs that need to be able to allocate memory, must take an instance of `aws_allocator` and use that. No `malloc()` or
`free()` calls should be made directly.
* If an API does not allocate the memory, it does not free it. All allocations and deallocations should take place at the same level.
For example, if a user allocates memory, the user is responsible for freeing it. There will inevitably be a few exceptions to this
rule, but they will need significant justification to make it through the code-review.
* All functions that allocate memory must raise an `AWS_ERROR_OOM` error code upon allocation failures. If it is a `new()` function
it should return NULL. If it is an `init()` function, it should return `AWS_OP_ERR`.
#### Threading
* Occasionally a thread is necessary. In those cases, prefer for memory not to be shared between threads. If memory must cross
a thread barrier it should be a complete ownership hand-off. Bias towards, "if I need a mutex, I'm doing it wrong".
* Do not sleep or block .... ever .... under any circumstances, in non-test-code.
* Do not expose blocking APIs.
### Error Handling
* For APIs returning an `int` error code. The only acceptable return types are `AWS_OP_SUCCESS` and `AWS_OP_ERR`. Before
returning control to the caller, if you have an error to raise, use the `aws_raise_error()` function.
* For APIs returning an allocated instance of an object, return the memory on success, and `NULL` on failure. Before
returning control to the caller, if you have an error to raise, use the `aws_raise_error()` function.
#### Log Subjects & Error Codes
The logging & error handling infrastructure is designed to support multiple libraries. For this to work, AWS maintained libraries
have pre-slotted log subjects & error codes for each library. The currently allocated ranges are:
| Range | Library Name |
| --- | --- |
| [0x0000, 0x0400) | aws-c-common |
| [0x0400, 0x0800) | aws-c-io |
| [0x0800, 0x0C00) | aws-c-http |
| [0x0C00, 0x1000) | aws-c-compression |
| [0x1000, 0x1400) | aws-c-eventstream |
| [0x1400, 0x1800) | aws-c-mqtt |
| [0x1800, 0x1C00) | aws-c-auth |
| [0x1C00, 0x2000) | aws-c-cal |
| [0x2000, 0x2400) | aws-crt-cpp |
| [0x2400, 0x2800) | aws-crt-java |
| [0x2800, 0x2C00) | aws-crt-python |
| [0x2C00, 0x3000) | aws-crt-nodejs |
| [0x3000, 0x3400) | aws-crt-dotnet |
| [0x3400, 0x3800) | aws-c-iot |
| [0x3800, 0x3C00) | (reserved for future project) |
| [0x3C00, 0x4000) | (reserved for future project) |
| [0x4000, 0x4400) | (reserved for future project) |
| [0x4400, 0x4800) | (reserved for future project) |
Each library should begin its error and log subject values at the beginning of its range and follow in sequence (don't skip codes). Upon
adding an AWS maintained library, a new enum range must be approved and added to the above table.
### Testing
We have a high bar for test coverage, and PRs fixing bugs or introducing new functionality need to have tests before
they will be accepted. A couple of tips:
#### Aws Test Harness
We provide a test harness for writing unit tests. This includes an allocator that will fail your test if you have any
memory leaks, as well as some `ASSERT` macros. To write a test:
* Create a *.c test file in the tests directory of the project.
* Implement one or more tests with the signature `int test_case_name(struct aws_allocator *, void *ctx)`
* Use the `AWS_TEST_CASE` macro to declare the test.
* Include your test in the `tests/main.c` file.
* Include your test in the `tests/CMakeLists.txt` file.
### Coding Style
* No Tabs.
* Indent is 4 spaces.
* K & R style for braces.
* Space after if, before the `(`.
* `else` and `else if` stay on the same line as the closing brace.
Example:
if (condition) {
do_something();
} else {
do_something_else();
}
* Avoid C99 features in header files. For some types such as bool, uint32_t etc..., these are defined if not available for the language
standard being used in `aws/common/common.h`, so feel free to use them.
* For C++ compatibility, don't put const members in structs.
* Avoid C++ style comments e.g. `//`.
* All public API functions need C++ guards and Windows dll semantics.
* Use Unix line endings.
* Where implementation hiding is desired for either ABI or runtime polymorphism reasons, use the `void *impl` pattern. v-tables
should be the last member in the struct.
* For #ifdef, put a # as the first character on the line and then indent the compilation branches.
Example:
#ifdef FOO
do_something();
# ifdef BAR
do_something_else();
# endif
#endif
* For all error code names with the exception of aws-c-common, use `AWS_ERROR_<lib name>_<error name>`.
* All error strings should be written using correct English grammar.
* SNAKE_UPPER_CASE constants, macros, and enum members.
* snake_lower_case everything else.
* `static` (local file scope) variables that are not `const` are prefixed by `s_` and lower snake case.
* Global variables not prefixed as `const` are prefixed by `g_` and lower snake case.
* Thread local variables are prefixed as `tl_` and lower snake case.
* Macros and `const` variables are upper snake case.
* For constants, prefer anonymous enums.
* Don't typedef structs. It breaks forward declaration ability.
* Don't typedef enums. It breaks forward declaration ability.
* typedef function definitions for use as function pointers as values and suffixed with _fn.
Example:
typedef int(fn_name_fn)(void *);
Not:
typedef int(*fn_name_fn)(void *);
* Every source and header file must have a copyright header (The standard AWS one for apache 2).
* Use standard include guards (e.g. #IFNDEF HEADER_NAME #define HEADER_NAME etc...).
* Include order should be:
the header for the translation unit for the .c file
newline
header files in a directory in alphabetical order
newline
header files not in a directory (system and stdlib headers)
* Platform specifics should be handled in c files and partitioned by directory.
* Do not use `extern inline`. It's too unpredictable between compiler versions and language standards.
* Namespace all definitions in header files with `aws_<libname>?_<api>_<what it does>`. Lib name is
not always required if a conflict is not likely and it provides better ergonomics.
* `init`, `clean_up`, `new`, `destroy` are suffixed to the function names for their object.
Example:
AWS_COMMON_API
int aws_module_init(aws_module_t *module);
AWS_COMMON_API
void aws_module_clean_up(aws_module_t *module);
AWS_COMMON_API
aws_module_t *aws_module_new(aws_allocator_t *allocator);
AWS_COMMON_API
void aws_module_destroy(aws_module_t *module);
* Avoid c-strings, and don't write code that depends on `NULL` terminators. Expose `struct aws_byte_buf` APIs
and let the user figure it out.
* There is only one valid character encoding-- UTF-8. Try not to ever need to care about character encodings, but
where you do, the working assumption should always be UTF-8 unless it's something we don't get a choice in (e.g. a protocol
explicitly mandates a character set).
* If you are adding/using a compiler specific keyword, macro, or intrinsic, hide it behind a platform independent macro
definition. This mainly applies to header files. Obviously, if you are writing a file that will only be built on a certain
platform, you have more liberty on this.
* When checking more than one error condition, check and log each condition separately with a unique message.
Example:
if (options->callback == NULL) {
AWS_LOGF_ERROR(AWS_LS_SOME_SUBJECT, "Invalid options - callback is null");
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
if (options->allocator == NULL) {
AWS_LOGF_ERROR(AWS_LS_SOME_SUBJECT, "Invalid options - allocator is null");
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
Not:
if (options->callback == NULL || options->allocator == NULL) {
AWS_LOGF_ERROR(AWS_LS_SOME_SUBJECT, "Invalid options - something is null");
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
|