| |
1 /* |
| |
2 * nmconn.c |
| |
3 * |
| |
4 * Copyright (c) 2004 Novell, Inc. All Rights Reserved. |
| |
5 * |
| |
6 * This program is free software; you can redistribute it and/or modify |
| |
7 * it under the terms of the GNU General Public License as published by |
| |
8 * the Free Software Foundation; version 2 of the License. |
| |
9 * |
| |
10 * This program is distributed in the hope that it will be useful, |
| |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
13 * GNU General Public License for more details. |
| |
14 * |
| |
15 * You should have received a copy of the GNU General Public License |
| |
16 * along with this program; if not, write to the Free Software |
| |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
18 * |
| |
19 */ |
| |
20 |
| |
21 #include <glib.h> |
| |
22 #include <unistd.h> |
| |
23 #include <errno.h> |
| |
24 #include <string.h> |
| |
25 #include <ctype.h> |
| |
26 #include <time.h> |
| |
27 #include "nmconn.h" |
| |
28 |
| |
29 #ifdef _WIN32 |
| |
30 #include <windows.h> |
| |
31 #endif |
| |
32 |
| |
33 #define NO_ESCAPE(ch) ((ch == 0x20) || (ch >= 0x30 && ch <= 0x39) || \ |
| |
34 (ch >= 0x41 && ch <= 0x5a) || (ch >= 0x61 && ch <= 0x7a)) |
| |
35 |
| |
36 /* Read data from conn until the end of a line */ |
| |
37 static NMERR_T |
| |
38 read_line(NMConn * conn, char *buff, int len) |
| |
39 { |
| |
40 NMERR_T rc = NM_OK; |
| |
41 int total_bytes = 0; |
| |
42 |
| |
43 while ((rc == NM_OK) && (total_bytes < (len - 1))) { |
| |
44 rc = nm_read_all(conn, &buff[total_bytes], 1); |
| |
45 if (rc == NM_OK) { |
| |
46 total_bytes += 1; |
| |
47 if (buff[total_bytes - 1] == '\n') { |
| |
48 break; |
| |
49 } |
| |
50 } |
| |
51 } |
| |
52 buff[total_bytes] = '\0'; |
| |
53 |
| |
54 return rc; |
| |
55 } |
| |
56 |
| |
57 static char * |
| |
58 url_escape_string(char *src) |
| |
59 { |
| |
60 guint32 escape = 0; |
| |
61 char *p; |
| |
62 char *q; |
| |
63 char *encoded = NULL; |
| |
64 int ch; |
| |
65 |
| |
66 static const char hex_table[16] = "0123456789abcdef"; |
| |
67 |
| |
68 if (src == NULL) { |
| |
69 return NULL; |
| |
70 } |
| |
71 |
| |
72 /* Find number of chars to escape */ |
| |
73 for (p = src; *p != '\0'; p++) { |
| |
74 ch = (guchar) *p; |
| |
75 if (!NO_ESCAPE(ch)) { |
| |
76 escape++; |
| |
77 } |
| |
78 } |
| |
79 |
| |
80 encoded = g_malloc((p - src) + (escape * 2) + 1); |
| |
81 |
| |
82 /* Escape the string */ |
| |
83 for (p = src, q = encoded; *p != '\0'; p++) { |
| |
84 ch = (guchar) * p; |
| |
85 if (NO_ESCAPE(ch)) { |
| |
86 if (ch != 0x20) { |
| |
87 *q = ch; |
| |
88 q++; |
| |
89 } else { |
| |
90 *q = '+'; |
| |
91 q++; |
| |
92 } |
| |
93 } else { |
| |
94 *q = '%'; |
| |
95 q++; |
| |
96 |
| |
97 *q = hex_table[ch >> 4]; |
| |
98 q++; |
| |
99 |
| |
100 *q = hex_table[ch & 15]; |
| |
101 q++; |
| |
102 } |
| |
103 } |
| |
104 *q = '\0'; |
| |
105 |
| |
106 return encoded; |
| |
107 } |
| |
108 |
| |
109 static char * |
| |
110 encode_method(guint8 method) |
| |
111 { |
| |
112 char *str; |
| |
113 |
| |
114 switch (method) { |
| |
115 case NMFIELD_METHOD_EQUAL: |
| |
116 str = "G"; |
| |
117 break; |
| |
118 case NMFIELD_METHOD_UPDATE: |
| |
119 str = "F"; |
| |
120 break; |
| |
121 case NMFIELD_METHOD_GTE: |
| |
122 str = "E"; |
| |
123 break; |
| |
124 case NMFIELD_METHOD_LTE: |
| |
125 str = "D"; |
| |
126 break; |
| |
127 case NMFIELD_METHOD_NE: |
| |
128 str = "C"; |
| |
129 break; |
| |
130 case NMFIELD_METHOD_EXIST: |
| |
131 str = "B"; |
| |
132 break; |
| |
133 case NMFIELD_METHOD_NOTEXIST: |
| |
134 str = "A"; |
| |
135 break; |
| |
136 case NMFIELD_METHOD_SEARCH: |
| |
137 str = "9"; |
| |
138 break; |
| |
139 case NMFIELD_METHOD_MATCHBEGIN: |
| |
140 str = "8"; |
| |
141 break; |
| |
142 case NMFIELD_METHOD_MATCHEND: |
| |
143 str = "7"; |
| |
144 break; |
| |
145 case NMFIELD_METHOD_NOT_ARRAY: |
| |
146 str = "6"; |
| |
147 break; |
| |
148 case NMFIELD_METHOD_OR_ARRAY: |
| |
149 str = "5"; |
| |
150 break; |
| |
151 case NMFIELD_METHOD_AND_ARRAY: |
| |
152 str = "4"; |
| |
153 break; |
| |
154 case NMFIELD_METHOD_DELETE_ALL: |
| |
155 str = "3"; |
| |
156 break; |
| |
157 case NMFIELD_METHOD_DELETE: |
| |
158 str = "2"; |
| |
159 break; |
| |
160 case NMFIELD_METHOD_ADD: |
| |
161 str = "1"; |
| |
162 break; |
| |
163 default: /* NMFIELD_METHOD_VALID */ |
| |
164 str = "0"; |
| |
165 break; |
| |
166 } |
| |
167 |
| |
168 return str; |
| |
169 } |
| |
170 |
| |
171 NMConn * |
| |
172 nm_create_conn(const char *addr, int port) |
| |
173 { |
| |
174 NMConn *conn = g_new0(NMConn, 1); |
| |
175 conn->addr = g_strdup(addr); |
| |
176 conn->port = port; |
| |
177 return conn; |
| |
178 } |
| |
179 |
| |
180 void nm_release_conn(NMConn *conn) |
| |
181 { |
| |
182 if (conn) { |
| |
183 GSList *node; |
| |
184 for (node = conn->requests; node; node = node->next) { |
| |
185 if (node->data) |
| |
186 nm_release_request(node->data); |
| |
187 } |
| |
188 g_slist_free(conn->requests); |
| |
189 conn->requests = NULL; |
| |
190 if (conn->ssl_conn) { |
| |
191 g_free(conn->ssl_conn); |
| |
192 conn->ssl_conn = NULL; |
| |
193 } |
| |
194 g_free(conn->addr); |
| |
195 conn->addr = NULL; |
| |
196 g_free(conn); |
| |
197 } |
| |
198 } |
| |
199 |
| |
200 int |
| |
201 nm_tcp_write(NMConn * conn, const void *buff, int len) |
| |
202 { |
| |
203 if (conn == NULL || buff == NULL) |
| |
204 return -1; |
| |
205 |
| |
206 if (!conn->use_ssl) |
| |
207 return (write(conn->fd, buff, len)); |
| |
208 else if (conn->ssl_conn && conn->ssl_conn->write) |
| |
209 return (conn->ssl_conn->write(conn->ssl_conn->data, buff, len)); |
| |
210 else |
| |
211 return -1; |
| |
212 } |
| |
213 |
| |
214 int |
| |
215 nm_tcp_read(NMConn * conn, void *buff, int len) |
| |
216 { |
| |
217 if (conn == NULL || buff == NULL) |
| |
218 return -1; |
| |
219 |
| |
220 if (!conn->use_ssl) |
| |
221 return (read(conn->fd, buff, len)); |
| |
222 else if (conn->ssl_conn && conn->ssl_conn->read) |
| |
223 return ((conn->ssl_conn->read)(conn->ssl_conn->data, buff, len)); |
| |
224 else |
| |
225 return -1; |
| |
226 } |
| |
227 |
| |
228 NMERR_T |
| |
229 nm_read_all(NMConn * conn, char *buff, int len) |
| |
230 { |
| |
231 NMERR_T rc = NM_OK; |
| |
232 int bytes_left = len; |
| |
233 int bytes_read; |
| |
234 int total_bytes = 0; |
| |
235 int retry = 1000; |
| |
236 |
| |
237 if (conn == NULL || buff == NULL) |
| |
238 return NMERR_BAD_PARM; |
| |
239 |
| |
240 /* Keep reading until buffer is full */ |
| |
241 while (bytes_left) { |
| |
242 bytes_read = nm_tcp_read(conn, &buff[total_bytes], bytes_left); |
| |
243 if (bytes_read > 0) { |
| |
244 bytes_left -= bytes_read; |
| |
245 total_bytes += bytes_read; |
| |
246 } else { |
| |
247 if (errno == EAGAIN) { |
| |
248 if (--retry == 0) { |
| |
249 rc = NMERR_TCP_READ; |
| |
250 break; |
| |
251 } |
| |
252 #ifdef _WIN32 |
| |
253 Sleep(1); |
| |
254 #else |
| |
255 usleep(1000); |
| |
256 #endif |
| |
257 } else { |
| |
258 rc = NMERR_TCP_READ; |
| |
259 break; |
| |
260 } |
| |
261 } |
| |
262 } |
| |
263 return rc; |
| |
264 } |
| |
265 |
| |
266 NMERR_T |
| |
267 nm_read_uint32(NMConn *conn, guint32 *val) |
| |
268 { |
| |
269 NMERR_T rc = NM_OK; |
| |
270 |
| |
271 rc = nm_read_all(conn, (char *)val, sizeof(*val)); |
| |
272 if (rc == NM_OK) { |
| |
273 *val = GUINT32_FROM_LE(*val); |
| |
274 } |
| |
275 |
| |
276 return rc; |
| |
277 } |
| |
278 |
| |
279 NMERR_T |
| |
280 nm_read_uint16(NMConn *conn, guint16 *val) |
| |
281 { |
| |
282 NMERR_T rc = NM_OK; |
| |
283 |
| |
284 rc = nm_read_all(conn, (char *)val, sizeof(*val)); |
| |
285 if (rc == NM_OK) { |
| |
286 *val = GUINT16_FROM_LE(*val); |
| |
287 } |
| |
288 |
| |
289 return rc; |
| |
290 } |
| |
291 |
| |
292 NMERR_T |
| |
293 nm_write_fields(NMConn * conn, NMField * fields) |
| |
294 { |
| |
295 NMERR_T rc = NM_OK; |
| |
296 NMField *field; |
| |
297 char *value = NULL; |
| |
298 char *method = NULL; |
| |
299 char buffer[4096]; |
| |
300 int ret; |
| |
301 int bytes_to_send; |
| |
302 int val = 0; |
| |
303 |
| |
304 if (conn == NULL || fields == NULL) { |
| |
305 return NMERR_BAD_PARM; |
| |
306 } |
| |
307 |
| |
308 /* Format each field as valid "post" data and write it out */ |
| |
309 for (field = fields; (rc == NM_OK) && (field->tag); field++) { |
| |
310 |
| |
311 /* We don't currently handle binary types */ |
| |
312 if (field->method == NMFIELD_METHOD_IGNORE || |
| |
313 field->type == NMFIELD_TYPE_BINARY) { |
| |
314 continue; |
| |
315 } |
| |
316 |
| |
317 /* Write the field tag */ |
| |
318 bytes_to_send = g_snprintf(buffer, sizeof(buffer), "&tag=%s", field->tag); |
| |
319 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
320 if (ret < 0) { |
| |
321 rc = NMERR_TCP_WRITE; |
| |
322 } |
| |
323 |
| |
324 /* Write the field method */ |
| |
325 if (rc == NM_OK) { |
| |
326 method = encode_method(field->method); |
| |
327 bytes_to_send = g_snprintf(buffer, sizeof(buffer), "&cmd=%s", method); |
| |
328 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
329 if (ret < 0) { |
| |
330 rc = NMERR_TCP_WRITE; |
| |
331 } |
| |
332 } |
| |
333 |
| |
334 /* Write the field value */ |
| |
335 if (rc == NM_OK) { |
| |
336 switch (field->type) { |
| |
337 case NMFIELD_TYPE_UTF8: |
| |
338 case NMFIELD_TYPE_DN: |
| |
339 |
| |
340 value = url_escape_string((char *) field->ptr_value); |
| |
341 bytes_to_send = g_snprintf(buffer, sizeof(buffer), |
| |
342 "&val=%s", value); |
| |
343 if (bytes_to_send > (int)sizeof(buffer)) { |
| |
344 ret = nm_tcp_write(conn, buffer, sizeof(buffer)); |
| |
345 } else { |
| |
346 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
347 } |
| |
348 |
| |
349 if (ret < 0) { |
| |
350 rc = NMERR_TCP_WRITE; |
| |
351 } |
| |
352 |
| |
353 g_free(value); |
| |
354 |
| |
355 break; |
| |
356 |
| |
357 case NMFIELD_TYPE_ARRAY: |
| |
358 case NMFIELD_TYPE_MV: |
| |
359 |
| |
360 val = nm_count_fields((NMField *) field->ptr_value); |
| |
361 bytes_to_send = g_snprintf(buffer, sizeof(buffer), |
| |
362 "&val=%u", val); |
| |
363 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
364 if (ret < 0) { |
| |
365 rc = NMERR_TCP_WRITE; |
| |
366 } |
| |
367 |
| |
368 break; |
| |
369 |
| |
370 default: |
| |
371 |
| |
372 bytes_to_send = g_snprintf(buffer, sizeof(buffer), |
| |
373 "&val=%u", field->value); |
| |
374 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
375 if (ret < 0) { |
| |
376 rc = NMERR_TCP_WRITE; |
| |
377 } |
| |
378 |
| |
379 break; |
| |
380 } |
| |
381 } |
| |
382 |
| |
383 /* Write the field type */ |
| |
384 if (rc == NM_OK) { |
| |
385 bytes_to_send = g_snprintf(buffer, sizeof(buffer), |
| |
386 "&type=%u", field->type); |
| |
387 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
388 if (ret < 0) { |
| |
389 rc = NMERR_TCP_WRITE; |
| |
390 } |
| |
391 } |
| |
392 |
| |
393 /* If the field is a sub array then post its fields */ |
| |
394 if (rc == NM_OK && val > 0) { |
| |
395 if (field->type == NMFIELD_TYPE_ARRAY || |
| |
396 field->type == NMFIELD_TYPE_MV) { |
| |
397 |
| |
398 rc = nm_write_fields(conn, (NMField *) field->ptr_value); |
| |
399 |
| |
400 } |
| |
401 } |
| |
402 } |
| |
403 |
| |
404 return rc; |
| |
405 } |
| |
406 |
| |
407 NMERR_T |
| |
408 nm_send_request(NMConn *conn, char *cmd, NMField *fields, |
| |
409 nm_response_cb cb, gpointer data, NMRequest **request) |
| |
410 { |
| |
411 NMERR_T rc = NM_OK; |
| |
412 char buffer[512]; |
| |
413 int bytes_to_send; |
| |
414 int ret; |
| |
415 NMField *request_fields = NULL; |
| |
416 char *str = NULL; |
| |
417 |
| |
418 if (conn == NULL || cmd == NULL) |
| |
419 return NMERR_BAD_PARM; |
| |
420 |
| |
421 /* Write the post */ |
| |
422 bytes_to_send = g_snprintf(buffer, sizeof(buffer), |
| |
423 "POST /%s HTTP/1.0\r\n", cmd); |
| |
424 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
425 if (ret < 0) { |
| |
426 rc = NMERR_TCP_WRITE; |
| |
427 } |
| |
428 |
| |
429 /* Write headers */ |
| |
430 if (rc == NM_OK) { |
| |
431 if (strcmp("login", cmd) == 0) { |
| |
432 bytes_to_send = g_snprintf(buffer, sizeof(buffer), |
| |
433 "Host: %s:%d\r\n\r\n", conn->addr, conn->port); |
| |
434 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
435 if (ret < 0) { |
| |
436 rc = NMERR_TCP_WRITE; |
| |
437 } |
| |
438 } else { |
| |
439 bytes_to_send = g_snprintf(buffer, sizeof(buffer), "\r\n"); |
| |
440 ret = nm_tcp_write(conn, buffer, bytes_to_send); |
| |
441 if (ret < 0) { |
| |
442 rc = NMERR_TCP_WRITE; |
| |
443 } |
| |
444 } |
| |
445 } |
| |
446 |
| |
447 /* Add the transaction id to the request fields */ |
| |
448 if (rc == NM_OK) { |
| |
449 if (fields) |
| |
450 request_fields = nm_copy_field_array(fields); |
| |
451 |
| |
452 str = g_strdup_printf("%d", ++(conn->trans_id)); |
| |
453 request_fields = nm_field_add_pointer(request_fields, NM_A_SZ_TRANSACTION_ID, 0, |
| |
454 NMFIELD_METHOD_VALID, 0, |
| |
455 str, NMFIELD_TYPE_UTF8); |
| |
456 } |
| |
457 |
| |
458 /* Send the request to the server */ |
| |
459 if (rc == NM_OK) { |
| |
460 rc = nm_write_fields(conn, request_fields); |
| |
461 } |
| |
462 |
| |
463 /* Write the CRLF to terminate the data */ |
| |
464 if (rc == NM_OK) { |
| |
465 ret = nm_tcp_write(conn, "\r\n", strlen("\r\n")); |
| |
466 if (ret < 0) { |
| |
467 rc = NMERR_TCP_WRITE; |
| |
468 } |
| |
469 } |
| |
470 |
| |
471 /* Create a request struct, add it to our queue, and return it */ |
| |
472 if (rc == NM_OK) { |
| |
473 NMRequest *new_request = nm_create_request(cmd, conn->trans_id, |
| |
474 time(0), cb, NULL, data); |
| |
475 nm_conn_add_request_item(conn, new_request); |
| |
476 |
| |
477 /* Set the out param if it was sent in, otherwise release the request */ |
| |
478 if (request) |
| |
479 *request = new_request; |
| |
480 else |
| |
481 nm_release_request(new_request); |
| |
482 } |
| |
483 |
| |
484 if (request_fields != NULL) |
| |
485 nm_free_fields(&request_fields); |
| |
486 |
| |
487 return rc; |
| |
488 } |
| |
489 |
| |
490 NMERR_T |
| |
491 nm_read_header(NMConn * conn) |
| |
492 { |
| |
493 NMERR_T rc = NM_OK; |
| |
494 char buffer[512]; |
| |
495 char *ptr = NULL; |
| |
496 int i; |
| |
497 char rtn_buf[8]; |
| |
498 int rtn_code = 0; |
| |
499 |
| |
500 if (conn == NULL) |
| |
501 return NMERR_BAD_PARM; |
| |
502 |
| |
503 *buffer = '\0'; |
| |
504 rc = read_line(conn, buffer, sizeof(buffer)); |
| |
505 if (rc == NM_OK) { |
| |
506 |
| |
507 /* Find the return code */ |
| |
508 ptr = strchr(buffer, ' '); |
| |
509 if (ptr != NULL) { |
| |
510 ptr++; |
| |
511 |
| |
512 i = 0; |
| |
513 while (isdigit(*ptr) && (i < 3)) { |
| |
514 rtn_buf[i] = *ptr; |
| |
515 i++; |
| |
516 ptr++; |
| |
517 } |
| |
518 rtn_buf[i] = '\0'; |
| |
519 |
| |
520 if (i > 0) |
| |
521 rtn_code = atoi(rtn_buf); |
| |
522 } |
| |
523 } |
| |
524 |
| |
525 /* Finish reading header, in the future we might want to do more processing here */ |
| |
526 /* TODO: handle more general redirects in the future */ |
| |
527 while ((rc == NM_OK) && (strcmp(buffer, "\r\n") != 0)) { |
| |
528 rc = read_line(conn, buffer, sizeof(buffer)); |
| |
529 } |
| |
530 |
| |
531 if (rc == NM_OK && rtn_code == 301) |
| |
532 rc = NMERR_SERVER_REDIRECT; |
| |
533 |
| |
534 return rc; |
| |
535 } |
| |
536 |
| |
537 NMERR_T |
| |
538 nm_read_fields(NMConn * conn, int count, NMField ** fields) |
| |
539 { |
| |
540 NMERR_T rc = NM_OK; |
| |
541 guint8 type; |
| |
542 guint8 method; |
| |
543 guint32 val; |
| |
544 char tag[64]; |
| |
545 NMField *sub_fields = NULL; |
| |
546 char *str = NULL; |
| |
547 |
| |
548 if (conn == NULL || fields == NULL) |
| |
549 return NMERR_BAD_PARM; |
| |
550 |
| |
551 do { |
| |
552 if (count > 0) { |
| |
553 count--; |
| |
554 } |
| |
555 |
| |
556 /* Read the field type, method, and tag */ |
| |
557 rc = nm_read_all(conn, (char *)&type, sizeof(type)); |
| |
558 if (rc != NM_OK || type == 0) |
| |
559 break; |
| |
560 |
| |
561 rc = nm_read_all(conn, (char *)&method, sizeof(method)); |
| |
562 if (rc != NM_OK) |
| |
563 break; |
| |
564 |
| |
565 rc = nm_read_uint32(conn, &val); |
| |
566 if (rc != NM_OK) |
| |
567 break; |
| |
568 |
| |
569 if (val > sizeof(tag)) { |
| |
570 rc = NMERR_PROTOCOL; |
| |
571 break; |
| |
572 } |
| |
573 |
| |
574 rc = nm_read_all(conn, tag, val); |
| |
575 if (rc != NM_OK) |
| |
576 break; |
| |
577 |
| |
578 if (type == NMFIELD_TYPE_MV || type == NMFIELD_TYPE_ARRAY) { |
| |
579 |
| |
580 /* Read the subarray (first read the number of items in the array) */ |
| |
581 rc = nm_read_uint32(conn, &val); |
| |
582 if (rc != NM_OK) |
| |
583 break; |
| |
584 |
| |
585 if (val > 0) { |
| |
586 rc = nm_read_fields(conn, val, &sub_fields); |
| |
587 if (rc != NM_OK) |
| |
588 break; |
| |
589 } |
| |
590 |
| |
591 *fields = nm_field_add_pointer(*fields, tag, 0, method, |
| |
592 0, sub_fields, type); |
| |
593 |
| |
594 sub_fields = NULL; |
| |
595 |
| |
596 } else if (type == NMFIELD_TYPE_UTF8 || type == NMFIELD_TYPE_DN) { |
| |
597 |
| |
598 /* Read the string (first read the length) */ |
| |
599 rc = nm_read_uint32(conn, &val); |
| |
600 if (rc != NM_OK) |
| |
601 break; |
| |
602 |
| |
603 if (val >= NMFIELD_MAX_STR_LENGTH) { |
| |
604 rc = NMERR_PROTOCOL; |
| |
605 break; |
| |
606 } |
| |
607 |
| |
608 if (val > 0) { |
| |
609 str = g_new0(char, val + 1); |
| |
610 |
| |
611 rc = nm_read_all(conn, str, val); |
| |
612 if (rc != NM_OK) |
| |
613 break; |
| |
614 |
| |
615 *fields = nm_field_add_pointer(*fields, tag, 0, method, |
| |
616 0, str, type); |
| |
617 str = NULL; |
| |
618 } |
| |
619 |
| |
620 } else { |
| |
621 |
| |
622 /* Read the numerical value */ |
| |
623 rc = nm_read_uint32(conn, &val); |
| |
624 if (rc != NM_OK) |
| |
625 break; |
| |
626 |
| |
627 *fields = nm_field_add_number(*fields, tag, 0, method, |
| |
628 0, val, type); |
| |
629 } |
| |
630 |
| |
631 } while ((type != 0) && (count != 0)); |
| |
632 |
| |
633 |
| |
634 if (str != NULL) { |
| |
635 g_free(str); |
| |
636 } |
| |
637 |
| |
638 if (sub_fields != NULL) { |
| |
639 nm_free_fields(&sub_fields); |
| |
640 } |
| |
641 |
| |
642 return rc; |
| |
643 } |
| |
644 |
| |
645 void |
| |
646 nm_conn_add_request_item(NMConn * conn, NMRequest * request) |
| |
647 { |
| |
648 if (conn == NULL || request == NULL) |
| |
649 return; |
| |
650 |
| |
651 nm_request_add_ref(request); |
| |
652 conn->requests = g_slist_append(conn->requests, request); |
| |
653 } |
| |
654 |
| |
655 void |
| |
656 nm_conn_remove_request_item(NMConn * conn, NMRequest * request) |
| |
657 { |
| |
658 if (conn == NULL || request == NULL) |
| |
659 return; |
| |
660 |
| |
661 conn->requests = g_slist_remove(conn->requests, request); |
| |
662 nm_release_request(request); |
| |
663 } |
| |
664 |
| |
665 NMRequest * |
| |
666 nm_conn_find_request(NMConn * conn, int trans_id) |
| |
667 { |
| |
668 NMRequest *req = NULL; |
| |
669 GSList *itr = NULL; |
| |
670 |
| |
671 if (conn == NULL) |
| |
672 return NULL; |
| |
673 |
| |
674 itr = conn->requests; |
| |
675 while (itr) { |
| |
676 req = (NMRequest *) itr->data; |
| |
677 if (req != NULL && nm_request_get_trans_id(req) == trans_id) { |
| |
678 return req; |
| |
679 } |
| |
680 itr = g_slist_next(itr); |
| |
681 } |
| |
682 return NULL; |
| |
683 } |
| |
684 |
| |
685 const char * |
| |
686 nm_conn_get_addr(NMConn * conn) |
| |
687 { |
| |
688 if (conn == NULL) |
| |
689 return NULL; |
| |
690 else |
| |
691 return conn->addr; |
| |
692 } |
| |
693 |
| |
694 int |
| |
695 nm_conn_get_port(NMConn * conn) |
| |
696 { |
| |
697 if (conn == NULL) |
| |
698 return -1; |
| |
699 else |
| |
700 return conn->port; |
| |
701 } |