~network-manager/network-manager/ubuntu.hardy.07

« back to all changes in this revision

Viewing changes to src/nm-serial-device.c

(merge) RELEASE 0.7~~svn20080928t225540+eni0-0ubuntu1 to ubuntu/intrepid

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
 
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
2
 
3
3
#define _GNU_SOURCE  /* for strcasestr() */
4
4
 
363
363
 
364
364
gboolean
365
365
nm_serial_device_open (NMSerialDevice *device,
366
 
                                   NMSettingSerial *setting)
 
366
                       NMSettingSerial *setting)
367
367
{
368
368
        NMSerialDevicePrivate *priv;
369
369
        const char *iface;
414
414
        if (priv->pending_id)
415
415
                g_source_remove (priv->pending_id);
416
416
 
 
417
        if (priv->ppp_manager) {
 
418
                nm_ppp_manager_stop (priv->ppp_manager);
 
419
                g_object_unref (priv->ppp_manager);
 
420
                priv->ppp_manager = NULL;
 
421
        }
 
422
 
417
423
        if (priv->fd) {
418
424
                nm_debug ("Closing device '%s'", nm_device_get_iface (NM_DEVICE (device)));
419
425
 
433
439
{
434
440
        int fd;
435
441
        NMSettingSerial *setting;
436
 
        int i;
437
 
        ssize_t status;
 
442
        int i, eagain_count = 1000;
 
443
        ssize_t written;
 
444
        guint32 send_delay = G_USEC_PER_SEC / 1000;
438
445
 
439
446
        g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), FALSE);
440
447
        g_return_val_if_fail (command != NULL, FALSE);
441
448
 
442
449
        fd = NM_SERIAL_DEVICE_GET_PRIVATE (device)->fd;
443
450
        setting = NM_SETTING_SERIAL (serial_device_get_setting (device, NM_TYPE_SETTING_SERIAL));
 
451
        if (setting && setting->send_delay)
 
452
                send_delay = setting->send_delay;
444
453
 
445
454
        serial_debug ("Sending:", (char *) command->data, command->len);
446
455
 
447
 
        for (i = 0; i < command->len; i++) {
448
 
        again:
449
 
                status = write (fd, command->data + i, 1);
450
 
 
451
 
                if (status < 0) {
452
 
                        if (errno == EAGAIN)
453
 
                                goto again;
454
 
 
455
 
                        g_warning ("Error in writing (errno %d)", errno);
456
 
                        return FALSE;
 
456
        for (i = 0; i < command->len && eagain_count > 0;) {
 
457
                written = write (fd, command->data + i, 1);
 
458
 
 
459
                if (written > 0)
 
460
                        i += written;
 
461
                else {
 
462
                        /* Treat written == 0 as EAGAIN to ensure we break out of the
 
463
                         * for() loop eventually.
 
464
                         */
 
465
                        if ((written < 0) && (errno != EAGAIN)) {
 
466
                                g_warning ("Error in writing (errno %d)", errno);
 
467
                                return FALSE;
 
468
                        }
 
469
                        eagain_count--;
457
470
                }
458
 
 
459
 
                if (setting->send_delay)
460
 
                        usleep (setting->send_delay);
 
471
                g_usleep (send_delay);
461
472
        }
462
473
 
 
474
        if (eagain_count <= 0)
 
475
                serial_debug ("Error: too many retries sending:", (char *) command->data, command->len);
 
476
 
463
477
        return TRUE;
464
478
}
465
479
 
482
496
        return ret;
483
497
}
484
498
 
485
 
typedef struct {
486
 
        NMSerialDevice *device;
487
 
        char *terminators;
488
 
        GString *result;
489
 
        NMSerialGetReplyFn callback;
490
 
        gpointer user_data;
491
 
} GetReplyInfo;
492
 
 
493
 
static void
494
 
get_reply_done (gpointer data)
495
 
{
496
 
        GetReplyInfo *info = (GetReplyInfo *) data;
497
 
 
498
 
        nm_serial_device_pending_done (info->device);
499
 
 
500
 
        /* Call the callback */
501
 
        info->callback (info->device, info->result->str, info->user_data);
502
 
 
503
 
        /* Free info */
504
 
        g_free (info->terminators);
505
 
        g_string_free (info->result, TRUE);
506
 
 
507
 
        g_slice_free (GetReplyInfo, info);
508
 
}
509
 
 
510
499
static gboolean
511
 
get_reply_got_data (GIOChannel *source,
512
 
                                GIOCondition condition,
513
 
                                gpointer data)
514
 
{
515
 
        GetReplyInfo *info = (GetReplyInfo *) data;
516
 
        gsize bytes_read;
 
500
find_terminator (const char *line, const char **terminators)
 
501
{
 
502
        int i;
 
503
 
 
504
        for (i = 0; terminators[i]; i++) {
 
505
                if (!strncasecmp (line, terminators[i], strlen (terminators[i])))
 
506
                        return TRUE;
 
507
        }
 
508
        return FALSE;
 
509
}
 
510
 
 
511
static const char *
 
512
find_response (const char *line, const char **responses, gint *idx)
 
513
{
 
514
        int i;
 
515
 
 
516
        /* Don't look for a result again if we got one previously */
 
517
        for (i = 0; responses[i]; i++) {
 
518
                if (strcasestr (line, responses[i])) {
 
519
                        *idx = i;
 
520
                        return line;
 
521
                }
 
522
        }
 
523
        return NULL;
 
524
}
 
525
 
 
526
#define RESPONSE_LINE_MAX 128
 
527
 
 
528
int
 
529
nm_serial_device_wait_reply_blocking (NMSerialDevice *device,
 
530
                                      guint32 timeout_secs,
 
531
                                      const char **needles,
 
532
                                      const char **terminators)
 
533
{
517
534
        char buf[SERIAL_BUF_SIZE + 1];
518
 
        GIOStatus status;
 
535
        int fd, reply_index = -1, bytes_read;
 
536
        GString *result = NULL;
 
537
        time_t end;
 
538
        const char *response = NULL;
519
539
        gboolean done = FALSE;
520
 
        int i;
521
 
 
522
 
        if (condition & G_IO_HUP || condition & G_IO_ERR) {
523
 
                g_string_truncate (info->result, 0);
524
 
                return FALSE;
525
 
        }
526
 
 
 
540
 
 
541
        g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), -1);
 
542
        g_return_val_if_fail (timeout_secs <= 60, -1);
 
543
        g_return_val_if_fail (needles != NULL, -1);
 
544
 
 
545
        fd = NM_SERIAL_DEVICE_GET_PRIVATE (device)->fd;
 
546
        if (fd < 0)
 
547
                return -1;
 
548
 
 
549
        end = time (NULL) + timeout_secs;
 
550
        result = g_string_sized_new (20);
527
551
        do {
528
 
                GError *err = NULL;
529
 
 
530
 
                status = g_io_channel_read_chars (source, buf, SERIAL_BUF_SIZE, &bytes_read, &err);
531
 
                if (status == G_IO_STATUS_ERROR) {
532
 
                        g_warning ("%s", err->message);
533
 
                        g_error_free (err);
534
 
                        err = NULL;
535
 
                }
536
 
 
537
 
                if (bytes_read > 0) {
538
 
                        char *p;
539
 
 
540
 
                        serial_debug ("Got:", buf, bytes_read);
541
 
 
542
 
                        p = &buf[0];
543
 
                        for (i = 0; i < bytes_read && !done; i++, p++) {
544
 
                                int j;
545
 
                                gboolean is_terminator = FALSE;
546
 
 
547
 
                                for (j = 0; j < strlen (info->terminators); j++) {
548
 
                                        if (*p == info->terminators[j]) {
549
 
                                                is_terminator = TRUE;
550
 
                                                break;
 
552
                bytes_read = read (fd, buf, SERIAL_BUF_SIZE);
 
553
                if (bytes_read < 0 && errno != EAGAIN) {
 
554
                        nm_warning ("%s: read error: %d (%s)",
 
555
                                    nm_device_get_iface (NM_DEVICE (device)),
 
556
                                    errno,
 
557
                                    strerror (errno));
 
558
                        return -1;
 
559
                }
 
560
 
 
561
                if (bytes_read == 0)
 
562
                        break; /* EOF */
 
563
                else if (bytes_read > 0) {
 
564
                        buf[bytes_read] = 0;
 
565
                        g_string_append (result, buf);
 
566
 
 
567
                        serial_debug ("Got:", result->str, result->len);
 
568
                }
 
569
 
 
570
                /* Look for needles and terminators */
 
571
                if ((bytes_read > 0) && result->str) {
 
572
                        char *p = result->str;
 
573
 
 
574
                        /* Break the response up into lines and process each one */
 
575
                        while ((p < result->str + strlen (result->str)) && !done) {
 
576
                                char line[RESPONSE_LINE_MAX] = { '\0', };
 
577
                                char *tmp;
 
578
                                int i;
 
579
                                gboolean got_something = FALSE;
 
580
 
 
581
                                for (i = 0; *p && (i < RESPONSE_LINE_MAX - 1); p++) {
 
582
                                        /* Ignore front CR/LF */
 
583
                                        if ((*p == '\n') || (*p == '\r')) {
 
584
                                                if (got_something)
 
585
                                                        break;
 
586
                                        } else {
 
587
                                                line[i++] = *p;
 
588
                                                got_something = TRUE;
551
589
                                        }
552
590
                                }
 
591
                                line[i] = '\0';
553
592
 
554
 
                                if (is_terminator) {
555
 
                                        /* Ignore terminators in the beginning of the output */
556
 
                                        if (info->result->len > 0)
557
 
                                                done = TRUE;
558
 
                                } else
559
 
                                        g_string_append_c (info->result, *p);
 
593
                                tmp = g_strstrip (line);
 
594
                                if (tmp && strlen (tmp)) {
 
595
                                        done = find_terminator (tmp, terminators);
 
596
                                        if (reply_index == -1)
 
597
                                                response = find_response (tmp, needles, &reply_index);
 
598
                                }
560
599
                        }
561
600
                }
562
601
 
563
602
                /* Limit the size of the buffer */
564
 
                if (info->result->len > SERIAL_BUF_SIZE) {
 
603
                if (result->len > SERIAL_BUF_SIZE) {
565
604
                        g_warning ("%s (%s): response buffer filled before repsonse received",
566
 
                                   __func__, nm_device_get_iface (NM_DEVICE (info->device)));
567
 
                        g_string_truncate (info->result, 0);
568
 
                        done = TRUE;
 
605
                                   __func__, nm_device_get_iface (NM_DEVICE (device)));
 
606
                        break;
569
607
                }
570
 
        } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
571
 
 
572
 
        return !done;
573
 
}
574
 
 
575
 
guint
576
 
nm_serial_device_get_reply (NMSerialDevice *device,
577
 
                                           guint timeout,
578
 
                                           const char *terminators,
579
 
                                           NMSerialGetReplyFn callback,
580
 
                                           gpointer user_data)
581
 
{
582
 
        GetReplyInfo *info;
583
 
 
584
 
        g_return_val_if_fail (NM_IS_SERIAL_DEVICE (device), 0);
585
 
        g_return_val_if_fail (terminators != NULL, 0);
586
 
        g_return_val_if_fail (callback != NULL, 0);
587
 
 
588
 
        info = g_slice_new0 (GetReplyInfo);
589
 
        info->device = device;
590
 
        info->terminators = g_strdup (terminators);
591
 
        info->result = g_string_new (NULL);
592
 
        info->callback = callback;
593
 
        info->user_data = user_data;
594
 
 
595
 
        return nm_serial_device_set_pending (device, timeout, get_reply_got_data, info, get_reply_done);
 
608
 
 
609
                if (!done)
 
610
                        g_usleep (100);
 
611
        } while (!done && (time (NULL) < end));
 
612
 
 
613
        return reply_index;
596
614
}
597
615
 
598
616
typedef struct {
603
621
        NMSerialWaitForReplyFn callback;
604
622
        gpointer user_data;
605
623
        int reply_index;
606
 
        guint timeout;
607
 
        time_t start;
 
624
        char *reply_line;
 
625
        time_t end;
608
626
} WaitForReplyInfo;
609
627
 
610
628
static void
615
633
        nm_serial_device_pending_done (info->device);
616
634
 
617
635
        /* Call the callback */
618
 
        info->callback (info->device, info->reply_index, info->user_data);
 
636
        info->callback (info->device, info->reply_index, info->reply_line, info->user_data);
619
637
 
620
638
        /* Free info */
621
639
        if (info->result)
622
640
                g_string_free (info->result, TRUE);
623
641
 
 
642
        g_free (info->reply_line);
 
643
 
624
644
        g_strfreev (info->str_needles);
625
645
        g_strfreev (info->terminators);
626
646
        g_slice_free (WaitForReplyInfo, info);
627
647
}
628
648
 
629
649
static gboolean
630
 
find_terminator (const char *line, char **terminators)
631
 
{
632
 
        int i;
633
 
 
634
 
        for (i = 0; terminators[i]; i++) {
635
 
                if (!strncasecmp (line, terminators[i], strlen (terminators[i])))
636
 
                        return TRUE;
637
 
        }
638
 
        return FALSE;
639
 
}
640
 
 
641
 
static gboolean
642
 
find_response (const char *line, char **responses, gint *idx)
643
 
{
644
 
        int i;
645
 
 
646
 
        /* Don't look for a result again if we got one previously */
647
 
        for (i = 0; responses[i]; i++) {
648
 
                if (strcasestr (line, responses[i])) {
649
 
                        *idx = i;
650
 
                        return TRUE;
651
 
                }
652
 
        }
653
 
        return FALSE;
654
 
}
655
 
 
656
 
#define RESPONSE_LINE_MAX 128
657
 
 
658
 
static gboolean
659
650
wait_for_reply_got_data (GIOChannel *source,
660
651
                                        GIOCondition condition,
661
652
                                        gpointer data)
664
655
        gchar buf[SERIAL_BUF_SIZE + 1];
665
656
        gsize bytes_read;
666
657
        GIOStatus status;
667
 
        gboolean got_response = FALSE;
668
658
        gboolean done = FALSE;
669
659
 
670
660
        if (condition & G_IO_HUP || condition & G_IO_ERR)
692
682
                        char *p = info->result->str;
693
683
 
694
684
                        /* Break the response up into lines and process each one */
695
 
                        while (   (p < info->result->str + strlen (info->result->str))
696
 
                               && !(done && got_response)) {
 
685
                        while ((p < info->result->str + strlen (info->result->str)) && !done) {
697
686
                                char line[RESPONSE_LINE_MAX] = { '\0', };
698
687
                                char *tmp;
699
688
                                int i;
713
702
 
714
703
                                tmp = g_strstrip (line);
715
704
                                if (tmp && strlen (tmp)) {
716
 
                                        done = find_terminator (tmp, info->terminators);
717
 
                                        if (info->reply_index == -1)
718
 
                                                got_response = find_response (tmp, info->str_needles, &(info->reply_index));
 
705
                                        done = find_terminator (tmp, (const char **) info->terminators);
 
706
                                        if (info->reply_index == -1) {
 
707
                                                if (find_response (tmp, (const char **) info->str_needles, &(info->reply_index)))
 
708
                                                        info->reply_line = g_strdup (tmp);
 
709
                                        }
719
710
                                }
720
711
                        }
721
 
 
722
 
                        if (done && got_response)
723
 
                                break;
724
712
                }
725
713
 
726
714
                /* Limit the size of the buffer */
727
715
                if (info->result->len > SERIAL_BUF_SIZE) {
728
 
                        g_warning ("%s (%s): response buffer filled before repsonse received",
729
 
                                   __func__, nm_device_get_iface (NM_DEVICE (info->device)));
 
716
                        nm_warning ("(%s): response buffer filled before repsonse received",
 
717
                                    nm_device_get_iface (NM_DEVICE (info->device)));
730
718
                        done = TRUE;
731
719
                        break;
732
720
                }
736
724
                 * terminate (terminator not found, whatever) then this should make
737
725
                 * sure that NM doesn't spin the CPU forever.
738
726
                 */
739
 
                if (time (NULL) - info->start > info->timeout + 1) {
 
727
                if (time (NULL) > info->end) {
740
728
                        done = TRUE;
741
729
                        break;
742
 
                } else
 
730
                } else if (!done)
743
731
                        g_usleep (50);
744
732
        } while (!done || bytes_read == SERIAL_BUF_SIZE || status == G_IO_STATUS_AGAIN);
745
733
 
748
736
 
749
737
guint
750
738
nm_serial_device_wait_for_reply (NMSerialDevice *device,
751
 
                                                   guint timeout,
752
 
                                                   char **responses,
753
 
                                                   char **terminators,
754
 
                                                   NMSerialWaitForReplyFn callback,
755
 
                                                   gpointer user_data)
 
739
                                 guint timeout,
 
740
                                 const char **responses,
 
741
                                 const char **terminators,
 
742
                                 NMSerialWaitForReplyFn callback,
 
743
                                 gpointer user_data)
756
744
{
757
745
        WaitForReplyInfo *info;
758
746
 
762
750
 
763
751
        info = g_slice_new0 (WaitForReplyInfo);
764
752
        info->device = device;
765
 
        info->str_needles = g_strdupv (responses);
766
 
        info->terminators = g_strdupv (terminators);
 
753
        info->str_needles = g_strdupv ((char **) responses);
 
754
        info->terminators = g_strdupv ((char **) terminators);
767
755
        info->result = g_string_new (NULL);
768
756
        info->callback = callback;
769
757
        info->user_data = user_data;
770
758
        info->reply_index = -1;
771
 
        info->timeout = timeout;
772
 
        info->start = time (NULL);
 
759
        info->end = time (NULL) + timeout;
773
760
 
774
761
        return nm_serial_device_set_pending (device, timeout, wait_for_reply_got_data, info, wait_for_reply_done);
775
762
}
1074
1061
}
1075
1062
 
1076
1063
static void
1077
 
real_deactivate_quickly (NMDevice *device)
 
1064
cleanup_device (NMSerialDevice *device)
1078
1065
{
1079
 
        NMSerialDevice *self = NM_SERIAL_DEVICE (device);
1080
1066
        NMSerialDevicePrivate *priv = NM_SERIAL_DEVICE_GET_PRIVATE (device);
1081
1067
 
1082
 
        nm_device_set_ip_iface (device, NULL);
 
1068
        nm_device_set_ip_iface (NM_DEVICE (device), NULL);
1083
1069
 
1084
1070
        if (priv->pending_ip4_config) {
1085
1071
                g_object_unref (priv->pending_ip4_config);
1087
1073
        }
1088
1074
 
1089
1075
        priv->in_bytes = priv->out_bytes = 0;
1090
 
 
1091
 
        if (priv->ppp_manager) {
1092
 
                g_object_unref (priv->ppp_manager);
1093
 
                priv->ppp_manager = NULL;
1094
 
        }
1095
 
 
 
1076
}
 
1077
 
 
1078
static void
 
1079
real_deactivate_quickly (NMDevice *device)
 
1080
{
 
1081
        NMSerialDevice *self = NM_SERIAL_DEVICE (device);
 
1082
 
 
1083
        cleanup_device (self);
1096
1084
        nm_serial_device_close (self);
1097
1085
}
1098
1086
 
1114
1102
{
1115
1103
        NMSerialDevice *self = NM_SERIAL_DEVICE (object);
1116
1104
 
 
1105
        cleanup_device (self);
1117
1106
        nm_serial_device_close (self);
1118
1107
 
1119
1108
        G_OBJECT_CLASS (nm_serial_device_parent_class)->finalize (object);