Objectively 1.0.0
Ultra-lightweight object oriented framework for GNU C.
Macros | Functions | Variables
URLSession.c File Reference
#include <assert.h>
#include <curl/curl.h>
#include "URLSession.h"

Go to the source code of this file.

Macros

#define _Class   _URLSession
 

Functions

Class_URLSession (void)
 
static URLSessionDataTaskdataTaskWithRequest (URLSession *self, URLRequest *request, URLSessionTaskCompletion completion)
 
static URLSessionDataTaskdataTaskWithURL (URLSession *self, URL *url, URLSessionTaskCompletion completion)
 
static void dealloc (Object *self)
 
static void destroy (Class *clazz)
 
static URLSessionDownloadTaskdownloadTaskWithRequest (URLSession *self, URLRequest *request, URLSessionTaskCompletion completion)
 
static URLSessionDownloadTaskdownloadTaskWithURL (URLSession *self, URL *url, URLSessionTaskCompletion completion)
 
static URLSessioninit (URLSession *self)
 
static void initialize (Class *clazz)
 
static URLSessioninitWithConfiguration (URLSession *self, URLSessionConfiguration *configuration)
 
static void invalidateAndCancel (URLSession *self)
 
static ident run (Thread *thread)
 ThreadFunction for a URLSession. More...
 
static URLSessionsharedInstance (void)
 
static Arraytasks (const URLSession *self)
 
static ident taskWithRequest (URLSession *self, ident task, URLRequest *request, URLSessionTaskCompletion completion)
 URLSessionTask factory function. More...
 
static URLSessionUploadTaskuploadTaskWithRequest (URLSession *self, URLRequest *request, URLSessionTaskCompletion completion)
 

Variables

static URLSession_sharedInstance
 

Macro Definition Documentation

◆ _Class

#define _Class   _URLSession

Definition at line 30 of file URLSession.c.

Function Documentation

◆ _URLSession()

Class * _URLSession ( void  )

Definition at line 389 of file URLSession.c.

389 {
390 static Class *clazz;
391 static Once once;
392
393 do_once(&once, {
394 clazz = _initialize(&(const ClassDef) {
395 .name = "URLSession",
396 .superclass = _Object(),
397 .instanceSize = sizeof(URLSession),
398 .interfaceOffset = offsetof(URLSession, interface),
399 .interfaceSize = sizeof(URLSessionInterface),
401 .destroy = destroy,
402 });
403 });
404
405 return clazz;
406}
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition: Class.c:91
static void destroy(Class *clazz)
Definition: URLSession.c:378
static void initialize(Class *clazz)
Definition: URLSession.c:356
long Once
The Once type.
Definition: Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition: Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition: Class.h:41
The runtime representation of a Class.
Definition: Class.h:95
Class * _Object(void)
The Object archetype.
Definition: Object.c:136
A management context for loading resources via URLs.
Definition: URLSession.h:57

◆ dataTaskWithRequest()

static URLSessionDataTask * dataTaskWithRequest ( URLSession self,
URLRequest request,
URLSessionTaskCompletion  completion 
)
static

Definition at line 76 of file URLSession.c.

76 {
77
78 return taskWithRequest(self, alloc(URLSessionDataTask), request, completion);
79}
#define alloc(type)
Allocate and initialize and instance of type.
Definition: Class.h:159
static ident taskWithRequest(URLSession *self, ident task, URLRequest *request, URLSessionTaskCompletion completion)
URLSessionTask factory function.
Definition: URLSession.c:57
Use data tasks to send and receive Data in-memory.

◆ dataTaskWithURL()

static URLSessionDataTask * dataTaskWithURL ( URLSession self,
URL url,
URLSessionTaskCompletion  completion 
)
static

Definition at line 85 of file URLSession.c.

85 {
86
87 URLRequest *request = $(alloc(URLRequest), initWithURL, url);
88
89 URLSessionDataTask *task = $(self, dataTaskWithRequest, request, completion);
90
91 release(request);
92
93 return task;
94}
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition: Class.c:196
A protocol-agnostic abstraction for requesting resources via URLs.
Definition: URLRequest.h:56
URLRequest * initWithURL(URLRequest *self, URL *url)
Initializes this URLRequest with the specified URL.
Definition: URLRequest.c:73
URLSessionDataTask * dataTaskWithRequest(URLSession *, URLRequest *, URLSessionTaskCompletion)
Creates a URLSessionDataTask for the given URLRequest.
Definition: URLSession.c:76

◆ dealloc()

static void dealloc ( Object self)
static
See also
Object::dealloc(Object *)

Definition at line 37 of file URLSession.c.

37 {
38
39 URLSession *this = (URLSession *) self;
40
41 $(this, invalidateAndCancel);
42
43 $(this->locals.thread, join, NULL);
44
45 release(this->locals.condition);
46 release(this->locals.thread);
47 release(this->locals.tasks);
48
49 super(Object, self, dealloc);
50}
#define super(type, obj, method,...)
Object is the root Class of The Objectively Class hierarchy.
Definition: Object.h:46
void dealloc(Object *self)
Frees all resources held by this Object.
Definition: Array.c:50
void join(Thread *self, ident *status)
Wait for the specified Thread to terminate.
Definition: Thread.c:130
void invalidateAndCancel(URLSession *)
Invalidates this URLSession and cancels all pending tasks.
Definition: URLSession.c:290

◆ destroy()

static void destroy ( Class clazz)
static
See also
Class::destroy(Class *)

Definition at line 378 of file URLSession.c.

378 {
379
381
382 curl_global_cleanup();
383}
static URLSession * _sharedInstance
Definition: URLSession.c:310

◆ downloadTaskWithRequest()

static URLSessionDownloadTask * downloadTaskWithRequest ( URLSession self,
URLRequest request,
URLSessionTaskCompletion  completion 
)
static

Definition at line 100 of file URLSession.c.

100 {
101
102 return taskWithRequest(self, alloc(URLSessionDownloadTask), request, completion);
103}
Use download tasks to save remote resources to file.

◆ downloadTaskWithURL()

static URLSessionDownloadTask * downloadTaskWithURL ( URLSession self,
URL url,
URLSessionTaskCompletion  completion 
)
static

Definition at line 109 of file URLSession.c.

109 {
110
111 URLRequest *request = $(alloc(URLRequest), initWithURL, url);
112
113 URLSessionDownloadTask *task = $(self, downloadTaskWithRequest, request, completion);
114
115 release(request);
116
117 return task;
118}
URLSessionDownloadTask * downloadTaskWithRequest(URLSession *, URLRequest *, URLSessionTaskCompletion)
Creates a URLSessionDownloadTask for the given URLRequest.
Definition: URLSession.c:100

◆ init()

static URLSession * init ( URLSession self)
static

Definition at line 124 of file URLSession.c.

124 {
125
127
128 self = $(self, initWithConfiguration, configuration);
129
130 release(configuration);
131
132 return self;
133}
Condition * init(Condition *self)
Initializes this Condition.
Definition: Condition.c:67
Configuration bundle for URLSession.
URLSession * initWithConfiguration(URLSession *, URLSessionConfiguration *)
Initializes this URLSession with the given configuration.
Definition: URLSession.c:267

◆ initialize()

static void initialize ( Class clazz)
static
See also
Class::initialize(Class *)

Definition at line 356 of file URLSession.c.

356 {
357
358 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
359
360 ((URLSessionInterface *) clazz->interface)->dataTaskWithRequest = dataTaskWithRequest;
361 ((URLSessionInterface *) clazz->interface)->dataTaskWithURL = dataTaskWithURL;
362 ((URLSessionInterface *) clazz->interface)->downloadTaskWithRequest = downloadTaskWithRequest;
363 ((URLSessionInterface *) clazz->interface)->downloadTaskWithURL = downloadTaskWithURL;
364 ((URLSessionInterface *) clazz->interface)->init = init;
365 ((URLSessionInterface *) clazz->interface)->initWithConfiguration = initWithConfiguration;
366 ((URLSessionInterface *) clazz->interface)->invalidateAndCancel = invalidateAndCancel;
367 ((URLSessionInterface *) clazz->interface)->sharedInstance = sharedInstance;
368 ((URLSessionInterface *) clazz->interface)->tasks = tasks;
369 ((URLSessionInterface *) clazz->interface)->uploadTaskWithRequest = uploadTaskWithRequest;
370
371 const CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
372 assert(code == CURLE_OK);
373}
ident interface
The interface of the Class.
Definition: Class.h:105
Log * sharedInstance(void)
Definition: Log.c:212
Object * init(Object *self)
Initializes this Object.
Definition: Object.c:83
URLSessionDataTask * dataTaskWithURL(URLSession *, URL *, URLSessionTaskCompletion)
Creates a URLSessionDataTask for the given URL.
Definition: URLSession.c:85
URLSessionDownloadTask * downloadTaskWithURL(URLSession *, URL *, URLSessionTaskCompletion)
Creates a URLSessionDownloadTask for the given URL.
Definition: URLSession.c:109
URLSessionUploadTask * uploadTaskWithRequest(URLSession *, URLRequest *, URLSessionTaskCompletion)
Creates a URLSessionUploadTask for the given URLRequest.
Definition: URLSession.c:346
Array * tasks(const URLSession *)
Definition: URLSession.c:331

◆ initWithConfiguration()

static URLSession * initWithConfiguration ( URLSession self,
URLSessionConfiguration configuration 
)
static

Definition at line 267 of file URLSession.c.

267 {
268
269 assert(configuration);
270
271 self = (URLSession *) super(Object, self, init);
272 if (self) {
273 self->configuration = retain(configuration);
274
275 self->locals.condition = $(alloc(Condition), init);
276 self->locals.lock = $(alloc(Lock), init);
277 self->locals.tasks = $(alloc(MutableArray), init);
278 self->locals.thread = $(alloc(Thread), initWithFunction, run, self);
279
280 $(self->locals.thread, start);
281 }
282
283 return self;
284}
ident retain(ident obj)
Atomically increment the given Object's reference count.
Definition: Class.c:211
static ident run(Thread *thread)
ThreadFunction for a URLSession.
Definition: URLSession.c:138
POSIX Threads conditional variables.
Definition: Condition.h:44
POSIX Threads locks.
Definition: Lock.h:42
Mutable arrays.
Definition: MutableArray.h:40
void start(Operation *self)
Starts this Operation.
Definition: Operation.c:171
Operation * initWithFunction(Operation *self, OperationFunction function, ident data)
Initializes a synchronous Operation with the given function.
Definition: Operation.c:119
POSIX Threads.
Definition: Thread.h:53
Lock * lock
The Lock guarding access to tasks.
Definition: URLSession.h:87
Condition * condition
The condition.
Definition: URLSession.h:77
URLSessionConfiguration * configuration
The session configuration.
Definition: URLSession.h:103
Thread * thread
The backing Thread.
Definition: URLSession.h:97
MutableArray * tasks
The URLSessionTasks.
Definition: URLSession.h:92

◆ invalidateAndCancel()

static void invalidateAndCancel ( URLSession self)
static

Definition at line 290 of file URLSession.c.

290 {
291
292 if (self->locals.thread->isCancelled) {
293 return;
294 }
295
296 Array *tasks = $(self, tasks);
297
298 for (size_t i = 0; i < tasks->count; i++) {
299
300 URLSessionTask *task = $(tasks, objectAtIndex, i);
301 $(task, cancel);
302 }
303
304 release(tasks);
305
306 $(self->locals.thread, cancel);
307 $(self->locals.condition, signal);
308}
Immutable arrays.
Definition: Array.h:56
ident objectAtIndex(const Array *self, int index)
size_t count
The count of elements.
Definition: Array.h:72
void signal(Condition *self)
Signals a single Thread waiting on this Condition.
void cancel(Operation *self)
Cancels this Operation, allowing it to complete immediately.
Definition: Operation.c:74
_Bool isCancelled
true when this Thread has been cancelled, false otherwise.
Definition: Thread.h:79
URL session tasks are handles to pending URL operations.

◆ run()

static ident run ( Thread thread)
static

ThreadFunction for a URLSession.

Definition at line 138 of file URLSession.c.

138 {
139
140 URLSession *self = thread->data;
141
142 self->locals.handle = curl_multi_init();
143 assert(self->locals.handle);
144
145 while (true) {
146 int ret;
147
148 Array *tasks = $(self, tasks);
149 if (tasks->count == 0) {
150
151 if (thread->isCancelled) {
152 break;
153 }
154
155 $(self->locals.condition, wait);
156 continue;
157 }
158
159 for (size_t i = 0; i < tasks->count; i++) {
160
161 URLSessionTask *task = $(tasks, objectAtIndex, i);
162 if (task->state == URLSESSIONTASK_SUSPENDING) {
163
164 if (task->locals.handle) {
165 const CURLcode err = curl_easy_pause(task->locals.handle, CURLPAUSE_ALL);
166 assert(err == CURLE_OK);
167 }
168
170
171 } else if (task->state == URLSESSIONTASK_RESUMING) {
172
173 if (task->locals.handle == NULL) {
174
175 $(task, setup);
176 assert(task->locals.handle);
177
178 const CURLMcode merr = curl_multi_add_handle(self->locals.handle, task->locals.handle);
179 assert(merr == CURLM_OK);
180 } else {
181 const CURLcode err = curl_easy_pause(task->locals.handle, CURLPAUSE_CONT);
182 assert(err == CURLE_OK);
183 }
184
186
187 } else if (task->state == URLSESSIONTASK_CANCELING) {
188
189 if (task->locals.handle) {
190 const CURLMcode merr = curl_multi_remove_handle(self->locals.handle, task->locals.handle);
191 assert(merr == CURLM_OK);
192 }
193
195
196 if (task->completion) {
197 task->completion(task, false);
198 }
199
200 $(task, teardown);
201
202 synchronized(self->locals.lock, {
203 $(self->locals.tasks, removeObject, task);
204 });
205 } else if (task->state == URLSESSIONTASK_COMPLETED) {
206
207 synchronized(self->locals.lock, {
208 $(self->locals.tasks, removeObject, task);
209 });
210 }
211 }
212
213 CURLMcode merr = curl_multi_wait(self->locals.handle, NULL, 0, 0, NULL);
214 assert(merr == CURLM_OK);
215
216 merr = curl_multi_perform(self->locals.handle, &ret);
217 assert(merr == CURLM_OK);
218
219 CURLMsg *message;
220 while ((message = curl_multi_info_read(self->locals.handle, &ret))) {
221
222 URLSessionTask *task = NULL;
223 for (size_t i = 0; i < tasks->count; i++) {
224
226 if (t->locals.handle == message->easy_handle) {
227 task = t;
228 break;
229 }
230 }
231
232 assert(task);
233
234 if (message->msg == CURLMSG_DONE) {
235
236 merr = curl_multi_remove_handle(self->locals.handle, task->locals.handle);
237 assert(merr == CURLM_OK);
238
240
241 curl_easy_getinfo(task->locals.handle, CURLINFO_RESPONSE_CODE, (long *) &task->response->httpStatusCode);
242
243 if (task->completion) {
244 task->completion(task, message->data.result == CURLE_OK);
245 }
246
247 $(task, teardown);
248
249 synchronized(self->locals.lock, {
250 $(self->locals.tasks, removeObject, task);
251 });
252 }
253 }
254
255 release(tasks);
256 }
257
258 curl_multi_cleanup(self->locals.handle);
259
260 return NULL;
261}
@ URLSESSIONTASK_RESUMING
@ URLSESSIONTASK_CANCELED
@ URLSESSIONTASK_SUSPENDING
@ URLSESSIONTASK_SUSPENDED
@ URLSESSIONTASK_COMPLETED
@ URLSESSIONTASK_RESUMED
@ URLSESSIONTASK_CANCELING
void wait(Condition *self)
Waits indefinitely for this Condition to be signaled.
void removeObject(MutableArray *self, const ident obj)
Removes the specified Object from this MutableArray.
Definition: MutableArray.c:270
ident data
The user data.
Definition: Thread.h:69
int httpStatusCode
The HTTP response status code.
Definition: URLResponse.h:63
ident handle
The libcurl handle.
Definition: URLSession.h:82
struct URLResponse * response
The response.
ident handle
The backing libcurl handle.
void setup(URLSessionTask *)
Sets up this task.
void teardown(URLSessionTask *)
Tears down this task.
URLSessionTaskState state
The state.
URLSessionTaskCompletion completion
The completion function.

◆ sharedInstance()

static URLSession * sharedInstance ( void  )
static

Definition at line 316 of file URLSession.c.

316 {
317
318 static Once once;
319
320 do_once(&once, {
322 });
323
324 return _sharedInstance;
325}

◆ tasks()

static Array * tasks ( const URLSession self)
static

Definition at line 331 of file URLSession.c.

331 {
332
333 Array *array;
334
335 synchronized(self->locals.lock, {
336 array = $$(Array, arrayWithArray, (Array *) self->locals.tasks);
337 });
338
339 return array;
340}
Array * arrayWithArray(const Array *array)
Returns a new Array containing the contents of array.
Definition: Array.c:133
MutableArray * array(void)
Returns a new MutableArray.
Definition: MutableArray.c:153

◆ taskWithRequest()

static ident taskWithRequest ( URLSession self,
ident  task,
URLRequest request,
URLSessionTaskCompletion  completion 
)
static

URLSessionTask factory function.

Definition at line 57 of file URLSession.c.

57 {
58
59 task = $((URLSessionTask *) task, initWithRequestInSession, request, self, completion);
60 if (task) {
61
62 synchronized(self->locals.lock, {
63 $(self->locals.tasks, addObject, task);
64 });
65
66 $(self->locals.condition, signal);
67 }
68
69 return task;
70}
void addObject(MutableArray *self, const ident obj)
Adds the specified Object to this MutableArray.
Definition: MutableArray.c:99
URLSessionTask * initWithRequestInSession(URLSessionTask *, struct URLRequest *, struct URLSession *, URLSessionTaskCompletion)
Initializes this task with the given URLRequest.

◆ uploadTaskWithRequest()

static URLSessionUploadTask * uploadTaskWithRequest ( URLSession self,
URLRequest request,
URLSessionTaskCompletion  completion 
)
static

Definition at line 346 of file URLSession.c.

346 {
347
348 return taskWithRequest(self, alloc(URLSessionUploadTask), request, completion);
349}
Use upload tasks to send files directly from disk.

Variable Documentation

◆ _sharedInstance

URLSession* _sharedInstance
static

Definition at line 310 of file URLSession.c.